I know I’m missing something basic. I’m trying to dynamically compile a class and then reload it after a change. The following code works. However, when I call it twice (once after changing the .java), the class definition does not update. What am I missing?
File file = new File("/eraseme/Eraseme.java");
File[] files = new File[] {file};
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(files);
CompilationTask task = compiler.getTask(null, fileManager, null, null,null,compilationUnits);
boolean madeIt = task.call(); // works
File classFile = new File("/eraseme/Eraseme.class");
URL url = classFile.toURL();
URL[] urls = new URL[] { url };
ClassLoader cl = new URLClassLoader(urls);
Class cls = cl.loadClass("Eraseme");
TestApi test = (TestApi) cls.newInstance();
System.out.println(test.getVersion());
What you’re missing is that the urls passed to
URLClassLoadershould be directories that are then searched. What’s happening is that theURLClassLoaderthat you’re constructing isn’t actually finding the .class file, but is failing to find the class and is falling back to having the parent classloader load the class.Specifically, try modifying the second bit of your code to be:
Note that if your class is called (with the package)
com.mycompany.erasestuff.EraseMe, then the classloader will look in the file/eraseme/com/mycompany/erasestuff/EraseMe.classNote that when you do this, you don’t want the system classloader to be able to load the
EraseMeclass. The system classloader will take precedence, and yourURLClassloaderwon’t load anything. (The unfortunate thing is that when you say to a classloader “load this class”, it first checks whether its parent classloader can load the class, then it tries to load it itself. If the system classloader can load this class, you’ll never get a different version)