Skip to content

Instantly share code, notes, and snippets.

@kk17
Created March 10, 2017 10:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kk17/caf462f08cb32567548f4e62380315c1 to your computer and use it in GitHub Desktop.
Save kk17/caf462f08cb32567548f4e62380315c1 to your computer and use it in GitHub Desktop.
A Java ClassLoader that can load classes from Java source file. This ClassLoader can't compile recursively.
package test;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class DynamicCompileClassLoader extends URLClassLoader {
private String sourceInputFolder;
private String classOutputFolder;
private JavaCompiler compiler;
private DynamicCompileClassLoader(URL[] urls, String sourceInputFolder,
String classOutputFolder, ClassLoader classLoader) {
super(urls, classLoader);
this.sourceInputFolder = sourceInputFolder;
this.classOutputFolder = classOutputFolder;
this.compiler = ToolProvider.getSystemJavaCompiler();
}
public static DynamicCompileClassLoader create(String sourceInputFolder,
String classOutputFolder, ClassLoader classLoader) {
File outputDir = new File(classOutputFolder);
if (!outputDir.exists()) {
outputDir.mkdirs();
}
URL url = null;
try {
url = outputDir.toURI().toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
}
return new DynamicCompileClassLoader(new URL[] {url}, sourceInputFolder, classOutputFolder,
classLoader);
}
public Class<?> findClass(String qualifiedClassName) throws ClassNotFoundException {
String filepath = Paths.get("", qualifiedClassName.split("\\.")).toString();
Path path = Paths.get(sourceInputFolder, filepath + ".java");
File sourceFile = path.toFile();
if (!sourceFile.exists()) {
return super.findClass(qualifiedClassName);
}
File classFile = Paths.get(classOutputFolder, filepath + ".class").toFile();
if (classFile.exists()) {
if (!sourceFile.exists() || classFile.lastModified() > sourceFile.lastModified()) {
return super.findClass(qualifiedClassName);
}
}
compileClassFile(sourceFile);
return super.findClass(qualifiedClassName);
}
private void compileClassFile(File sourceFile) {
Iterable<String> options = Arrays.asList("-d", classOutputFolder);
try (StandardJavaFileManager fileManager =
compiler.getStandardFileManager(null, null, null)) {
Iterable<? extends JavaFileObject> fileObjects =
fileManager.getJavaFileObjects(sourceFile);
JavaCompiler.CompilationTask task =
compiler.getTask(null, null, null, options, null, fileObjects);
Boolean result = task.call();
if (result == null || !result.booleanValue()) {
throw new RuntimeException(
"Compilation failed. class file path:" + sourceFile.getPath());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
DynamicCompileClassLoader dcc = DynamicCompileClassLoader.create("demo", "demo_class",
DynamicCompileClassLoader.class.getClassLoader());
Class<?> class1 = dcc.loadClass("Test1");
System.out.println(class1.getName());
Class<?> class2 = dcc.loadClass("Test2");
System.out.println(class2.getName());
}
}
public class Test1 {
public static void main(String[] args) {
System.out.println("Test1 compiled.");
}
}
public class Test2 extends Test1{
public void foo(){
System.out.println("bar");
}
public static void main(String[] args) {
System.out.println("Test2 compiled.");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment