DynamicClassLoader.java

package com.alibaba.fastjson2.util;

import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.NameFilter;
import com.alibaba.fastjson2.filter.PropertyFilter;
import com.alibaba.fastjson2.filter.PropertyPreFilter;
import com.alibaba.fastjson2.filter.ValueFilter;
import com.alibaba.fastjson2.reader.*;
import com.alibaba.fastjson2.writer.*;

import java.lang.reflect.Type;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DynamicClassLoader
        extends ClassLoader {
    private static java.security.ProtectionDomain DOMAIN;

    private static Map<String, Class<?>> classMapping = new HashMap<>();

    private static DynamicClassLoader instance = new DynamicClassLoader();

    private Map<String, Class> classes = new ConcurrentHashMap<>();

    static {
        Class[] classes = new Class[]{
                Object.class,
                Type.class,

                Fnv.class,

                // reads
                JSONReader.class,

                FieldReader.class,

                ObjectReader.class,
                ObjectReader1.class,
                ObjectReader2.class,
                ObjectReader3.class,
                ObjectReader4.class,
                ObjectReader5.class,
                ObjectReader6.class,
                ObjectReader6.class,
                ObjectReader7.class,
                ObjectReader8.class,
                ObjectReader9.class,
                ObjectReader10.class,
                ObjectReader11.class,
                ObjectReader12.class,
                ObjectReaderAdapter.class,

                // writers

                JSONWriter.class,
                JSONWriter.Context.class,
                FieldWriter.class,

                PropertyPreFilter.class,
                PropertyFilter.class,
                NameFilter.class,
                ValueFilter.class,

                ObjectWriter.class,
                ObjectWriter1.class,
                ObjectWriter2.class,
                ObjectWriter3.class,
                ObjectWriter4.class,
                ObjectWriter5.class,
                ObjectWriter6.class,
                ObjectWriter7.class,
                ObjectWriter8.class,
                ObjectWriter9.class,
                ObjectWriter10.class,
                ObjectWriter11.class,
                ObjectWriter12.class,
                ObjectWriterAdapter.class,
                UnsafeUtils.class,

                java.util.Collection.class,
                java.util.List.class,
                java.util.Map.class,
                java.util.function.Supplier.class,
                java.lang.Enum.class,
                java.lang.Class.class,
                java.lang.String.class
        };
        for (Class clazz : classes) {
            classMapping.put(clazz.getName(), clazz);
        }
    }

    static {
        DOMAIN = (java.security.ProtectionDomain) java.security.AccessController.doPrivileged(
                (PrivilegedAction<Object>) () -> DynamicClassLoader.class.getProtectionDomain()
        );
    }

    private final ClassLoader parent;

    public DynamicClassLoader() {
        this(getParentClassLoader());
    }

    public DynamicClassLoader(ClassLoader parent) {
        super(parent);
        this.parent = parent;
    }

    static ClassLoader getParentClassLoader() {
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        if (contextClassLoader != null) {
            try {
                contextClassLoader.loadClass(DynamicClassLoader.class.getName());
                return contextClassLoader;
            } catch (ClassNotFoundException e) {
                // skip
            }
        }
        return DynamicClassLoader.class.getClassLoader();
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        Class<?> mappingClass = classMapping.get(name);
        if (mappingClass != null) {
            return mappingClass;
        }

        Class clazz = classes.get(name);
        if (clazz != null) {
            return clazz;
        }

        ClassNotFoundException error = null;
        try {
            return super.loadClass(name, resolve);
        } catch (ClassNotFoundException e) {
            error = e;
        }

        ClassLoader tcl = Thread.currentThread().getContextClassLoader();
        if (tcl != null && tcl != this) {
            try {
                return tcl.loadClass(name);
            } catch (ClassNotFoundException ignored) {
                // ignored
            }
        }

        throw error;
    }

    public void definePackage(String name) throws ClassFormatError {
        if (getPackage(name) != null) {
            return;
        }
        super.definePackage(name, "", "", "", "", "", "", null);
    }

    public Class<?> loadClass(String name, byte[] b, int off, int len) throws ClassFormatError {
        Class<?> clazz = defineClass(name, b, off, len, DOMAIN);
        classes.put(name, clazz);
        return clazz;
    }

    public Class<?> defineClassPublic(String name, byte[] b, int off, int len) throws ClassFormatError {
        return defineClass(name, b, off, len, DOMAIN);
    }

    public boolean isExternalClass(Class<?> clazz) {
        ClassLoader classLoader = clazz.getClassLoader();

        if (classLoader == null) {
            return false;
        }

        ClassLoader current = this;
        while (current != null) {
            if (current == classLoader) {
                return false;
            }

            current = current.getParent();
        }

        return true;
    }

    public void register(Class objectClass) {
        classMapping.put(objectClass.getName(), objectClass);
    }

    public static DynamicClassLoader getInstance() {
        return instance;
    }
}