When Texai learns a skill from a mentor, it will compose a Java method, format its source code, compile that class containing the method, and reload the revised class into the Java Virtual Machine (JVM) that is executing the local Texai instance. From various code samples and tutorials found on the web, I have assembled Java code that performs these operations. Because this is generally useful for Java developers, I am describing the steps in this post.
Dynamic compilation

The Java class to be compiled in this example is contained in the StringBuilder object stringBuilder. This set of code writes the stringBuilder to a file:

final String emittedSourceCodePath = “../data/generated/GeneratedTestImpl.java”;
final String formattedSourceCodePath = “../src/org/texai/bl/generated/GeneratedTestImpl.java”;

BufferedWriter bufferedWriter = null;
try {
bufferedWriter = new BufferedWriter(new FileWriter(emittedSourceCodePath));
bufferedWriter.write(stringBuilder.toString());
} catch (IOException ex) {
fail(ex.getMessage());
} finally {
try {
bufferedWriter.close();
} catch (IOException ex) {
fail(ex.getMessage());
}
}

This bit of code formats the source code with the Jalopy code formatter.

final Jalopy jalopy = new Jalopy();
try {
jalopy.setInput(new File(emittedSourceCodePath));
jalopy.setOutput(new File(formattedSourceCodePath));
} catch (final FileNotFoundException ex) {
fail(ex.getMessage());
}
jalopy.format();

This code compiles the formatted source code and writes the class file to the destination directory:

final JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
final DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();

final StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(
diagnosticCollector,
null, // default locale
null); // default character set

Iterable<? extends JavaFileObject> compilationUnits =
fileManager.getJavaFileObjectsFromStrings(Arrays.asList(”/home/reed/svn/BehaviorLanguage/src/org/texai/bl/generated/GeneratedTestImpl.java”));

JavaCompiler.CompilationTask compilationTask = javaCompiler.getTask(
null, // output writer
fileManager,
diagnosticCollector,
Arrays.asList(”-verbose”, “-d”, “/home/reed/svn/BehaviorLanguage/build/classes”), // options
null, // classes
compilationUnits);
boolean success = compilationTask.call();
try {
fileManager.close();
} catch (final IOException ex) {
fail(ex.getMessage());
}

This code reloads the compiled class. The source code for ClassReloader.java is here.

Class clazz = null;
try {
clazz = classReloader.reloadClass(
“/home/reed/svn/BehaviorLanguage/build/classes/org/texai/bl/generated/GeneratedTestImpl.class”,
“org.texai.bl.generated.GeneratedTestImpl”);
} catch (final ClassNotFoundException ex) {
fail(ex.getMessage());
}

When designing a class for dynamic reloading, one should create an interface so that the dynamic reloaded class methods can be called without resorting to inefficient reflection. Otherwise the presence of the Class name in the source code will cause the system class loader to load the class when the containing class is loaded, not after dynamic recompilation as is desired. This code sample loads the test class and casts it to its interface. Then it is instantiated and a test method called. Note that these samples contain JUnit assertion statements that are not required in production code.

final Class[] constructorParameterTypes = {String.class};
Constructor constructor = null;
try {
constructor = clazz.getConstructor(constructorParameterTypes);
} catch (final NoSuchMethodException ex) {
fail(ex.getMessage());
}
assertNotNull(constructor);
GeneratedTest generatedTest = null;
final Object[] initargs = {”abc”};
try {
generatedTest = (GeneratedTest) constructor.newInstance(initargs);
} catch (final InstantiationException ex) {
fail(ex.getMessage());
} catch (final InvocationTargetException ex) {
fail(ex.getMessage());
} catch (final IllegalAccessException ex) {
fail(ex.getMessage());
}
assertNotNull(generatedTest);
assertEquals(”def47″, generatedTest.testMethod(”def”, 47));

ClassReloader.java source.

GeneratedTest.java source

GeneratedTestImpl.java source

BootstrapMethodsTest.java (JUnit test) source