将文本代码在内存中编译,解析成class对象

这个程序的起因是,在使用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对象之间依赖的问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值