com.taobao.arthas.compiler.DynamicCompiler Maven / Gradle / Ivy
package com.taobao.arthas.compiler;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class DynamicCompiler {
private final JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
private final StandardJavaFileManager standardFileManager;
private final List options = new ArrayList();
private final DynamicClassLoader dynamicClassLoader;
private final Collection compilationUnits = new ArrayList();
private final List> errors = new ArrayList>();
private final List> warnings = new ArrayList>();
public DynamicCompiler(ClassLoader classLoader) {
if (javaCompiler == null) {
throw new IllegalStateException(
"Can not load JavaCompiler from javax.tools.ToolProvider#getSystemJavaCompiler(),"
+ " please confirm the application running in JDK not JRE.");
}
standardFileManager = javaCompiler.getStandardFileManager(null, null, null);
options.add("-Xlint:unchecked");
dynamicClassLoader = new DynamicClassLoader(classLoader);
}
public void addSource(String className, String source) {
addSource(new StringSource(className, source));
}
public void addSource(JavaFileObject javaFileObject) {
compilationUnits.add(javaFileObject);
}
public Map> build() {
errors.clear();
warnings.clear();
JavaFileManager fileManager = new DynamicJavaFileManager(standardFileManager, dynamicClassLoader);
DiagnosticCollector collector = new DiagnosticCollector();
JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, collector, options, null,
compilationUnits);
try {
if (!compilationUnits.isEmpty()) {
boolean result = task.call();
if (!result || collector.getDiagnostics().size() > 0) {
for (Diagnostic extends JavaFileObject> diagnostic : collector.getDiagnostics()) {
switch (diagnostic.getKind()) {
case NOTE:
case MANDATORY_WARNING:
case WARNING:
warnings.add(diagnostic);
break;
case OTHER:
case ERROR:
default:
errors.add(diagnostic);
break;
}
}
if (!errors.isEmpty()) {
throw new DynamicCompilerException("Compilation Error", errors);
}
}
}
return dynamicClassLoader.getClasses();
} catch (Throwable e) {
throw new DynamicCompilerException(e, errors);
} finally {
compilationUnits.clear();
}
}
public Map buildByteCodes() {
errors.clear();
warnings.clear();
JavaFileManager fileManager = new DynamicJavaFileManager(standardFileManager, dynamicClassLoader);
DiagnosticCollector collector = new DiagnosticCollector();
JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, collector, options, null,
compilationUnits);
try {
if (!compilationUnits.isEmpty()) {
boolean result = task.call();
if (!result || collector.getDiagnostics().size() > 0) {
for (Diagnostic extends JavaFileObject> diagnostic : collector.getDiagnostics()) {
switch (diagnostic.getKind()) {
case NOTE:
case MANDATORY_WARNING:
case WARNING:
warnings.add(diagnostic);
break;
case OTHER:
case ERROR:
default:
errors.add(diagnostic);
break;
}
}
if (!errors.isEmpty()) {
throw new DynamicCompilerException("Compilation Error", errors);
}
}
}
return dynamicClassLoader.getByteCodes();
} catch (ClassFormatError e) {
throw new DynamicCompilerException(e, errors);
} finally {
compilationUnits.clear();
}
}
private List diagnosticToString(List> diagnostics) {
List diagnosticMessages = new ArrayList();
for (Diagnostic extends JavaFileObject> diagnostic : diagnostics) {
diagnosticMessages.add(
"line: " + diagnostic.getLineNumber() + ", message: " + diagnostic.getMessage(Locale.US));
}
return diagnosticMessages;
}
public List getErrors() {
return diagnosticToString(errors);
}
public List getWarnings() {
return diagnosticToString(warnings);
}
public ClassLoader getClassLoader() {
return dynamicClassLoader;
}
}