DynamicClassLoader.java

package com.alibaba.fastjson2.util;

import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.PropertyNamingStrategy;
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.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.PrivilegedAction;
import java.time.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

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

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

    private static final DynamicClassLoader instance = new DynamicClassLoader();

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

    static {
        Class[] classes = new Class[]{
                Object.class,
                Type.class,
                Field.class,
                Method.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,
                JDKUtils.class,
                TypeUtils.class,
                DateUtils.class,
                PropertyNamingStrategy.class,

                Collection.class,
                Set.class,
                List.class,
                ArrayList.class,
                LinkedList.class,
                Map.class,
                HashMap.class,
                LinkedHashMap.class,
                EnumSet.class,
                Optional.class,
                OptionalInt.class,
                OptionalLong.class,
                Date.class,
                Calendar.class,
                ConcurrentHashMap.class,

                java.util.function.Supplier.class,
                java.util.function.Consumer.class,
                Exception.class,
                Enum.class,
                Class.class,
                Boolean.class,
                Byte.class,
                Short.class,
                Integer.class,
                Long.class,
                Float.class,
                Double.class,
                String.class,
                BigInteger.class,
                BigDecimal.class,
                Instant.class,
                LocalTime.class,
                LocalDate.class,
                LocalDateTime.class,
                ZonedDateTime.class,
                CharArrayValueConsumer.class,
                ByteArrayValueConsumer.class
        };
        for (Class clazz : classes) {
            classMapping.put(clazz.getName(), clazz);
        }

        String[] strings = {
                "sun.misc.Unsafe",
                "java.sql.Timestamp",
                "java.sql.Date"
        };
        for (String string : strings) {
            try {
                Class<?> c = Class.forName(string);
                classMapping.put(string, c);
            } catch (ClassNotFoundException ignored) {
                // ignored
            }
        }
    }

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

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

    public DynamicClassLoader(ClassLoader parent) {
        super(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;
        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 static DynamicClassLoader getInstance() {
        return instance;
    }
}