JDK6中的源代码编译功能,网上给的示例一般都无法运行,会抛出ClassNotFoundException。
经过改良,主要原因是字节码输出的文件不对。现修改为输出到内存中。
经过改良,主要原因是字节码输出的文件不对。现修改为输出到内存中。
/**
* 字符串变为Class
*
* @author wuyuhou
*
*/
public class StringToClass {
public static void main(String[] args) throws Exception {
Class clazz = loadClass("com.test.CalculatorTest",
"package com.test;"
+ "public class CalculatorTest {"
+ " public int multiply(int multiplicand, int multiplier) {"
+ " System.out.print(multiplicand + \" * \");"
+ " System.out.print(multiplier + \" = \");"
+ " return multiplicand * multiplier;"
+ " }"
+ "}", StringToClass.class.getClassLoader());
Object instance = clazz.newInstance();
Method m = clazz.getMethod("multiply", new Class[] {
int.class, int.class
});
Object[] o = new Object[] {
3, 2
};
System.out.println(m.invoke(instance, o));
}
public static Class loadClass(String className, String javaSource, ClassLoader loader) throws ClassNotFoundException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
//源码Java对象
JavaFileObject sourceFileObject = new SimpleJavaFileObjectWrapper(className, Kind.SOURCE, javaSource, null);
//输出到内存中
ByteArrayOutputStream byteArrayOutput = new ByteArrayOutputStream();
//Class输出Java对象
JavaFileObject outputFileObject = new SimpleJavaFileObjectWrapper(className, Kind.CLASS, null, byteArrayOutput);
Iterable<JavaFileObject> files = Arrays.asList(sourceFileObject);
StandardJavaFileManager fileManager = new StandardJavaFileManagerWrapper(compiler.getStandardFileManager(null, null, null), outputFileObject);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, files);
task.call();
//字节码数组
byte[] classBytes = byteArrayOutput.toByteArray();
return new SimpleClassLoader(loader).loadClass(classBytes);
}
private static class SimpleClassLoader extends ClassLoader {
public SimpleClassLoader(ClassLoader parent) {
super(parent);
}
public Class<?> loadClass(byte[] classBytes) throws ClassNotFoundException {
return defineClass(null, classBytes, 0, classBytes.length);
}
}
private static class SimpleJavaFileObjectWrapper extends SimpleJavaFileObject {
private String javaSource = null;
private ByteArrayOutputStream byteArrayOutput = null;
public SimpleJavaFileObjectWrapper(String className, Kind kind, String javaSource, ByteArrayOutputStream byteArrayOutput) {
super(URI.create("string:///" + className.replace('.', '/') + kind.extension), kind);
this.javaSource = javaSource;
this.byteArrayOutput = byteArrayOutput;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return javaSource;
}
@Override
public OutputStream openOutputStream() throws IOException {
return byteArrayOutput;
}
}
private static class StandardJavaFileManagerWrapper implements StandardJavaFileManager {
private StandardJavaFileManager defaultWrapper = null;
private JavaFileObject outputFileObject = null;
public StandardJavaFileManagerWrapper(StandardJavaFileManager defaultWrapper, JavaFileObject outputFileObject) {
this.defaultWrapper = defaultWrapper;
this.outputFileObject = outputFileObject;
}
public ClassLoader getClassLoader(Location location) {
return defaultWrapper.getClassLoader(location);
}
public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException {
return defaultWrapper.list(location, packageName, kinds, recurse);
}
public String inferBinaryName(Location location, JavaFileObject file) {
return defaultWrapper.inferBinaryName(location, file);
}
public boolean handleOption(String current, Iterator<String> remaining) {
return defaultWrapper.handleOption(current, remaining);
}
public boolean hasLocation(Location location) {
return defaultWrapper.hasLocation(location);
}
public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException {
return defaultWrapper.getJavaFileForInput(location, className, kind);
}
// 输出重新定位,否则就会报出ClassNotFoundException
public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
if (outputFileObject != null) {
return outputFileObject;
}
return defaultWrapper.getJavaFileForOutput(location, className, kind, sibling);
}
public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
return defaultWrapper.getFileForInput(location, packageName, relativeName);
}
public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
return defaultWrapper.getFileForOutput(location, packageName, relativeName, sibling);
}
public void flush() throws IOException {
defaultWrapper.flush();
}
public void close() throws IOException {
defaultWrapper.close();
}
public int isSupportedOption(String option) {
return defaultWrapper.isSupportedOption(option);
}
public boolean isSameFile(FileObject a, FileObject b) {
return defaultWrapper.isSameFile(a, b);
}
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) {
return defaultWrapper.getJavaFileObjectsFromFiles(files);
}
public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
return defaultWrapper.getJavaFileObjects(files);
}
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
return defaultWrapper.getJavaFileObjectsFromStrings(names);
}
public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
return defaultWrapper.getJavaFileObjects(names);
}
public void setLocation(Location location, Iterable<? extends File> path) throws IOException {
defaultWrapper.setLocation(location, path);
}
public Iterable<? extends File> getLocation(Location location) {
return defaultWrapper.getLocation(location);
}
}
}