How do I programmatically compile and instantiate a Java class?

dynamic-loading, java, reflection

Solution

How do I load a Java Class that is not compiled?

You need to compile it first. This can be done programmatically with the `javax.tools` API. This only requires the JDK being installed at the local machine on top of JRE.

Here's a basic kickoff example (leaving obvious exception handling aside):

// Prepare source somehow.
String source = "package test; public class Test { static { System.out.println(\"hello\"); } public Test() { System.out.println(\"world\"); } }";

// Save source in .java file.
File root = Files.createTempDirectory("java").toFile();
File sourceFile = new File(root, "test/Test.java");
sourceFile.getParentFile().mkdirs();
Files.write(sourceFile.toPath(), source.getBytes(StandardCharsets.UTF_8));

// Compile source file.
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, sourceFile.getPath());

// Load and instantiate compiled class.
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { root.toURI().toURL() });
Class<?> cls = Class.forName("test.Test", true, classLoader); // Should print "hello".
Object instance = cls.getDeclaredConstructor().newInstance(); // Should print "world".
System.out.println(instance); // Should print "test.Test@hashcode".

Which yields like

hello
world
test.Test@cafebabe

Further use would be more easy if those classes `implements` a certain interface which is already in the classpath.

SomeInterface instance = (SomeInterface) cls.getDeclaredConstructor().newInstance();

Otherwise you need to involve the Reflection API to access and invoke the (unknown) methods/fields.

That said and unrelated to the actual problem:

properties.load(new FileInputStream(new File("ClassName.properties")));

Letting `java.io.File` rely on current working directory is recipe for portability trouble. Don't do that. Put that file in classpath and use `ClassLoader#getResourceAsStream()` with a classpath-relative path.

properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("ClassName.properties"));

Problem

I have the class name stored in a property file. I know that the classes store will implement IDynamicLoad. How do I instantiate the class dynamically? Right now I have ``` Properties foo = new Properties(); foo.load(new FileInputStream(new File("ClassName.properties"))); String class_name = foo.getProperty("class","DefaultClass"); //IDynamicLoad newClass = Class.forName(class_name).newInstance(); ``` Does the newInstance only load compiled .class files? How do I load a Java Class that is not compiled?

Original source

Related problems