com.softicar.platform.common.code.java.compiler.RuntimeCompiler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of platform-common Show documentation
Show all versions of platform-common Show documentation
The SoftiCAR Platform is a lightweight, Java-based library to create interactive business web applications.
package com.softicar.platform.common.code.java.compiler;
import com.softicar.platform.common.code.java.IJavaClassSourceCode;
import com.softicar.platform.common.core.exceptions.SofticarIOException;
import com.softicar.platform.common.core.java.classes.name.JavaClassName;
import com.softicar.platform.common.core.utils.CastUtils;
import com.softicar.platform.common.string.charset.Charsets;
import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;
/**
* A Java compiler that compiles source code at runtime.
*
* @author Oliver Richers
*/
public class RuntimeCompiler implements AutoCloseable {
private final JavaCompiler compiler;
private final RuntimeCompilerClassLoader classLoader;
private final InMemoryJavaFileManager fileManager;
private final Map sourceFiles;
@SuppressWarnings("resource")
public RuntimeCompiler() {
this.compiler = ToolProvider.getSystemJavaCompiler();
this.classLoader = new RuntimeCompilerClassLoader(getClass().getClassLoader());
this.fileManager = new InMemoryJavaFileManager(createStandardFileManager(), classLoader);
this.sourceFiles = new TreeMap<>();
}
private JavaFileManager createStandardFileManager() {
return compiler.getStandardFileManager(null, null, Charsets.UTF8);
}
@Override
public void close() {
try {
fileManager.close();
} catch (IOException exception) {
throw new SofticarIOException(exception);
}
}
public void addSourceCode(IJavaClassSourceCode sourceCode) {
addSourceCode(sourceCode.getClassName(), sourceCode.getSourceCode());
}
public void addSourceCode(JavaClassName className, CharSequence sourceCode) {
InMemoryJavaSourceFile sourceFile = new InMemoryJavaSourceFile(className, sourceCode);
sourceFiles.put(className, sourceFile);
fileManager.addSourceFile(sourceFile);
}
public void clear() {
classLoader.clear();
fileManager.clear();
sourceFiles.clear();
}
public Map> compile() {
// start compilation
DiagnosticCollector diagnosticCollector = new DiagnosticCollector<>();
CompilationTask task = compiler.getTask(null, fileManager, diagnosticCollector, null, null, sourceFiles.values());
Boolean success = task.call();
if (!success) {
throw new RuntimeCompilerException("Compilation failed.", sourceFiles.keySet(), diagnosticCollector.getDiagnostics());
}
try {
Map> compiledClasses = new TreeMap<>();
for (JavaClassName className: sourceFiles.keySet()) {
Class compiledClass = classLoader.loadClass(className.getCanonicalName());
compiledClasses.put(className, compiledClass);
}
return compiledClasses;
} catch (ClassNotFoundException | IllegalArgumentException | SecurityException exception) {
throw new RuntimeCompilerException(sourceFiles.keySet(), exception, diagnosticCollector.getDiagnostics());
}
}
public static Class compile(IJavaClassSourceCode sourceCode) {
return compile(sourceCode.getClassName(), sourceCode.getSourceCode());
}
public static Class compile(JavaClassName className, CharSequence sourceCode) {
try (RuntimeCompiler compiler = new RuntimeCompiler()) {
compiler.addSourceCode(className, sourceCode);
Map> compiledClasses = compiler.compile();
return CastUtils.cast(compiledClasses.get(className));
}
}
}