In MPS it is not entirely unusual to encounter a ClassCastException
like this:
java.lang.ClassCastException: class Foo cannot be cast to class Foo
(Foo is in unnamed module of loader jetbrains.mps.classloading.ModuleClassLoader @e21bbe4;
Foo is in unnamed module of loader jetbrains.mps.classloading.ModuleClassLoader @47f4b8b8)
This is caused by “hot” reloading in MPS. Each module (language or solution) has a Java classloader associated with it
(an instance of jetbrains.mps.classloading.ModuleClassLoader
). When the Java code of the module is recompiled, MPS
will throw away the old classloader and create a fresh classloader for the module. This new classloader will load the
new classes. Under the JVM rules classes from two different classloaders are considered different even if they have the
same name and the same bytecode.
Typically, old instances can be found in node user objects or in caches that you have built. The stack trace of the exception will probably give you a hint as to where the lingering object was found.
After you found the place where the error happens, the simplest tactic to avoid this error is to program
defensively. Even though you know that you always put an object of
class Foo
under key Bar
, check whether the object you retrieve is an instanceof Foo
before you use it, and treat
it as null
if it is not.
You can also subscribe to class loading notifications via ClassLoaderManager#addListener
and clear any caches when
relevant modules get unloaded, to help reduce memory leaks.
Also note that these reloading problems are much more likely to occur during language development. Language users usually don’t write any code that is supposed to be dynamically loaded into MPS so they are unlikely to hit any class reloading problems.