这个程序的起因是,在使用Optional自动生成工具时,需要找到class包,感觉不方便Optional自动生成工具,所以就到网络上寻找了一下自动解析文本到class对象的资料。经过修改去除不必要的操作之后,代码如下
package builder;
import javax.tools.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 功能描述:将文本代码在内存中编译,解析成class对象<br/>
* 注意事项:详见方法<br/>
* 创建:JRZ<br/>
* 创建时间:2017/9/15 10:38<br/>
*/
public enum DynamicEngine {
DYNAMIC_ENGINE;
private final JavaCompiler compiler;
private final CodeFileManager fileManager;
private final List<String> options;
private final ClassLoader classloader;
DynamicEngine() {
this.compiler = ToolProvider.getSystemJavaCompiler();
this.fileManager = new CodeFileManager();
this.options = new ArrayList<>();
this.options.add("-encoding");
this.options.add("UTF-8");
this.options.add("-classpath");
StringBuilder sb = new StringBuilder();
for (URL url : ((URLClassLoader) DynamicEngine.class.getClassLoader()).getURLs()) {
sb.append(url.getFile()).append(File.pathSeparator);
}
this.options.add(sb.toString());
this.classloader = new ClassLoader();
}
/**
* 将文本代码加载为字节码对象
*
* @param fullName 类全名,也就是包名+类名
* @param code 类内容
* @return 字节码对象
* @throws Exception 加载异常时
*/
public Class<?> code2Class(String fullName, String code) throws Exception {
StringCode sCode = new StringCode(fullName, code);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, Collections.singletonList(sCode));
if (!task.call()) {
throw new RuntimeException("生成字节码对象失败!");
}
return classloader.loadClass(fullName, fileManager.getByteCode());
}
private class StringCode extends SimpleJavaFileObject {
private String content;
StringCode(String className, String content) {
super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.content = content;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return content;
}
}
private class ByteCode extends SimpleJavaFileObject {
private final ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteCode(String name, Kind kind) {
super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind);
}
byte[] getBytes() {
return bos.toByteArray();
}
@Override
public OutputStream openOutputStream() throws IOException {
return bos;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
bos.close();
}
}
private class CodeFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
private ByteCode byteCode;
CodeFileManager() {
super(ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null));
}
@Override
public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
if (byteCode == null) {
byteCode = new ByteCode(className, kind);
}
return byteCode;
}
ByteCode getByteCode() {
return byteCode;
}
}
private class ClassLoader extends URLClassLoader {
private ClassLoader() {
super(new URL[0], ClassLoader.class.getClassLoader());
}
private Class loadClass(String fullName, ByteCode object) {
byte[] data = object.getBytes();
return this.defineClass(fullName, data, 0, data.length);
}
}
}
使用方法如下
package builder;
public class MyClass {
@Override
public String toString() {
return "hello" + this.getClass();
}
}
package builder;
import file.Util;
import java.io.File;
public class DynaCompTest {
public static void main(String[] args) throws Exception {
String fullName = "builder.MyClass";
File file = new File("F:\\Workspace\\IdeaProjects\\Scala\\src\\main\\java\\builder\\MyClass.java");
String src = Util.UTIL.read(file);
System.out.println(src);
Object instance = DynamicEngine.DYNAMIC_ENGINE.code2Class(fullName, src).newInstance();
System.out.println(instance);
}
}
通过这个工具和Optional生成工具组合,可以实现 根据文本内容生成Optional方法扩展类的功能;但是需要解决Bean对象之间依赖的问题