2017  Kodetalk | Feedback | Privacy Policy | Terms | About
userimage

How do I programmatically compile and instantiate a Java class?

Because of some of my project requirement I kept the classnames in a property file.

I know that the classes store will implement IDynamicLoad. How do I instantiate the class dynamically?

userimage

You can do it by programmatically with the help of javax.tools API. This only requires the JDK being installed at the local machine on top of JRE.

Just look at below 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 = new File("/java"); // On Windows running on C:, this is C:java.
File sourceFile = new File(root, "test/Test.java");
sourceFile.getParentFile().mkdirs();
Files.write(source, sourceFile, 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.newInstance(); // Should print "world".
System.out.println(instance); // Should print "test.Test@hashcode".

The output is:

hello
world
test.Test@ab853b

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

SomeInterface instance = (SomeInterface) cls.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:

roperties.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"));
Answer is