All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.fastjson2.reader.ObjectReaderCreatorDynamicCompile Maven / Gradle / Ivy

Go to download

Fastjson is a JSON processor (JSON parser + JSON generator) written in Java

There is a newer version: 2.0.53.android8
Show newest version
package com.alibaba.fastjson2.reader;

import com.alibaba.fastjson2.codegen.ObjectReaderGen;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.util.DynamicClassLoader;
import com.alibaba.fastjson2.util.JDKUtils;

import javax.tools.*;
import java.io.*;
import java.lang.reflect.Constructor;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class ObjectReaderCreatorDynamicCompile extends ObjectReaderCreator {
    public static final ObjectReaderCreatorDynamicCompile INSTANCE = new ObjectReaderCreatorDynamicCompile();

    @Override
    public  ObjectReader createObjectReader(Class objectType) {
        if (JDKUtils.JVM_VERSION >= 17 && !JDKUtils.JAVAC_UNNAMED) {
            return super.createObjectReader(objectType);
        }

        FieldReader[] fieldReaderArray = createFieldReaders(objectType, objectType);

        StringBuilder out = new StringBuilder();
        ObjectReaderGen gen = new ObjectReaderGen(objectType, out);
        gen.gen();

        String sourceCode = out.toString();

        ObjectReader objectReader;
        try {
            objectReader = compile(
                    gen.getPackageName()
                    , gen.getClassName()
                    , sourceCode
                    , new Class[]{FieldReader[].class}
                    , new Object[]{fieldReaderArray}
            );
        } catch (Exception e) {
            throw new JSONException("compile error", e);
        }

        return objectReader;
    }

    static DiagnosticCollector DIAGNOSTIC_COLLECTOR = new DiagnosticCollector<>();

    @SuppressWarnings("unchecked")
    public static  T compile(String packageName,
                                String className,
                                String sourceCode,
                                Class[] constructorParamTypes,
                                Object[] constructorParams) throws Exception {
        // 获取系统编译器实例
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        // 设置编译参数
        List options = new ArrayList<>();
        options.add("-source");
        options.add("1.8");
        options.add("-target");
        options.add("1.8");
        // 获取标准的Java文件管理器实例
        StandardJavaFileManager manager = compiler.getStandardFileManager(DIAGNOSTIC_COLLECTOR, null, null);
        // 初始化自定义类加载器
        JdkDynamicCompileClassLoader classLoader = new JdkDynamicCompileClassLoader();
        // 初始化自定义Java文件管理器实例
        JdkDynamicCompileJavaFileManager fileManager = new JdkDynamicCompileJavaFileManager(manager, classLoader);
        String qualifiedName = packageName + "." + className;
        // 构建Java源文件实例
        CharSequenceJavaFileObject javaFileObject = new CharSequenceJavaFileObject(className, sourceCode);
        // 添加Java源文件实例到自定义Java文件管理器实例中
        fileManager.addJavaFileObject(
                StandardLocation.SOURCE_PATH,
                packageName,
                className + CharSequenceJavaFileObject.JAVA_EXTENSION,
                javaFileObject
        );
        // 初始化一个编译任务实例
        JavaCompiler.CompilationTask compilationTask = compiler.getTask(
                null,
                fileManager,
                DIAGNOSTIC_COLLECTOR,
                options,
                null,
                Collections.singleton(javaFileObject)
        );
        Boolean result = compilationTask.call();
//        System.out.println(String.format("编译[%s]结果:%s", qualifiedName, result));
        if (!result) {
            Diagnostic diagnostic = DIAGNOSTIC_COLLECTOR.getDiagnostics().get(0);
            System.out.println(diagnostic);
            throw new JSONException("compile error. \n" + sourceCode);
        }
        Class klass = classLoader.loadClass(qualifiedName);
        Constructor constructor = klass.getDeclaredConstructor(constructorParamTypes);
        return (T) constructor.newInstance(constructorParams);
    }

    public static class CharSequenceJavaFileObject extends SimpleJavaFileObject {

        public static final String CLASS_EXTENSION = ".class";

        public static final String JAVA_EXTENSION = ".java";

        private static URI fromClassName(String className) {
            try {
                return new URI(className);
            } catch (URISyntaxException e) {
                throw new IllegalArgumentException(className, e);
            }
        }

        private ByteArrayOutputStream byteCode;
        private final CharSequence sourceCode;

        public CharSequenceJavaFileObject(String className, CharSequence sourceCode) {
            super(fromClassName(className + JAVA_EXTENSION), Kind.SOURCE);
            this.sourceCode = sourceCode;
        }

        public CharSequenceJavaFileObject(String fullClassName, Kind kind) {
            super(fromClassName(fullClassName), kind);
            this.sourceCode = null;
        }

        public CharSequenceJavaFileObject(URI uri, Kind kind) {
            super(uri, kind);
            this.sourceCode = null;
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
            return sourceCode;
        }

        @Override
        public InputStream openInputStream() {
            return new ByteArrayInputStream(getByteCode());
        }

        // 注意这个方法是编译结果回调的OutputStream,回调成功后就能通过下面的getByteCode()方法获取目标类编译后的字节码字节数组
        @Override
        public OutputStream openOutputStream() {
            return byteCode = new ByteArrayOutputStream();
        }

        public byte[] getByteCode() {
            return byteCode.toByteArray();
        }
    }

    public static class JdkDynamicCompileClassLoader extends DynamicClassLoader {

        public static final String CLASS_EXTENSION = ".class";

        private final Map javaFileObjectMap = new ConcurrentHashMap<>();

        public JdkDynamicCompileClassLoader() {
            super();
        }

        @Override
        protected Class findClass(String name) throws ClassNotFoundException {
            JavaFileObject javaFileObject = javaFileObjectMap.get(name);
            if (null != javaFileObject) {
                CharSequenceJavaFileObject charSequenceJavaFileObject = (CharSequenceJavaFileObject) javaFileObject;
                byte[] byteCode = charSequenceJavaFileObject.getByteCode();
                return defineClass(name, byteCode, 0, byteCode.length);
            }
            return super.findClass(name);
        }

        @Override
        public InputStream getResourceAsStream(String name) {
            if (name.endsWith(CLASS_EXTENSION)) {
                String qualifiedClassName = name.substring(0, name.length() - CLASS_EXTENSION.length()).replace('/', '.');
                CharSequenceJavaFileObject javaFileObject = (CharSequenceJavaFileObject) javaFileObjectMap.get(qualifiedClassName);
                if (null != javaFileObject && null != javaFileObject.getByteCode()) {
                    return new ByteArrayInputStream(javaFileObject.getByteCode());
                }
            }
            return super.getResourceAsStream(name);
        }

        /**
         * 暂时存放编译的源文件对象,key为全类名的别名(非URI模式),如club.throwable.compile.HelloService
         */
        void addJavaFileObject(String qualifiedClassName, JavaFileObject javaFileObject) {
            javaFileObjectMap.put(qualifiedClassName, javaFileObject);
        }

        Collection listJavaFileObject() {
            return Collections.unmodifiableCollection(javaFileObjectMap.values());
        }
    }

    public static class JdkDynamicCompileJavaFileManager extends ForwardingJavaFileManager {

        private final JdkDynamicCompileClassLoader classLoader;
        private final Map javaFileObjectMap = new ConcurrentHashMap<>();

        public JdkDynamicCompileJavaFileManager(JavaFileManager fileManager, JdkDynamicCompileClassLoader classLoader) {
            super(fileManager);
            this.classLoader = classLoader;
        }

        private static URI fromLocation(Location location, String packageName, String relativeName) {
            try {
                return new URI(location.getName() + '/' + packageName + '/' + relativeName);
            } catch (URISyntaxException e) {
                throw new IllegalArgumentException(e);
            }
        }

        @Override
        public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
            JavaFileObject javaFileObject = javaFileObjectMap.get(fromLocation(location, packageName, relativeName));
            if (null != javaFileObject) {
                return javaFileObject;
            }
            return super.getFileForInput(location, packageName, relativeName);
        }

        /**
         * 这里是编译器返回的同(源)Java文件对象,替换为CharSequenceJavaFileObject实现
         */
        @Override
        public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
            JavaFileObject javaFileObject = new CharSequenceJavaFileObject(className, kind);
            classLoader.addJavaFileObject(className, javaFileObject);
            return javaFileObject;
        }

        /**
         * 这里覆盖原来的类加载器
         */
        @Override
        public ClassLoader getClassLoader(Location location) {
            return classLoader;
        }

        @Override
        public String inferBinaryName(Location location, JavaFileObject file) {
            if (file instanceof CharSequenceJavaFileObject) {
                return file.getName();
            }
            return super.inferBinaryName(location, file);
        }

        @Override
        public Iterable list(Location location, String packageName, Set kinds, boolean recurse) throws IOException {
            Iterable superResult = super.list(location, packageName, kinds, recurse);
            List result = new ArrayList();
            // 这里要区分编译的Location以及编译的Kind
            if (location == StandardLocation.CLASS_PATH && kinds.contains(JavaFileObject.Kind.CLASS)) {
                // .class文件以及classPath下
                for (JavaFileObject file : javaFileObjectMap.values()) {
                    if (file.getKind() == JavaFileObject.Kind.CLASS && file.getName().startsWith(packageName)) {
                        result.add(file);
                    }
                }
                // 这里需要额外添加类加载器加载的所有Java文件对象
                result.addAll(classLoader.listJavaFileObject());
            } else if (location == StandardLocation.SOURCE_PATH && kinds.contains(JavaFileObject.Kind.SOURCE)) {
                // .java文件以及编译路径下
                for (JavaFileObject file : javaFileObjectMap.values()) {
                    if (file.getKind() == JavaFileObject.Kind.SOURCE && file.getName().startsWith(packageName)) {
                        result.add(file);
                    }
                }
            }
            for (JavaFileObject javaFileObject : superResult) {
                result.add(javaFileObject);
            }
            return result;
        }

        /**
         * 自定义方法,用于添加和缓存待编译的源文件对象
         */
        public void addJavaFileObject(Location location, String packageName, String relativeName, JavaFileObject javaFileObject) {
            javaFileObjectMap.put(fromLocation(location, packageName, relativeName), javaFileObject);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy