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

shade.com.alibaba.fastjson2.internal.asm.ASMUtils Maven / Gradle / Ivy

There is a newer version: 1.3.7
Show newest version
package com.alibaba.fastjson2.internal.asm;

import com.alibaba.fastjson2.*;
import com.alibaba.fastjson2.annotation.JSONType;
import com.alibaba.fastjson2.function.*;
import com.alibaba.fastjson2.reader.*;
import com.alibaba.fastjson2.schema.JSONSchema;
import com.alibaba.fastjson2.util.*;
import com.alibaba.fastjson2.writer.*;
import com.alibaba.fastjson2.writer.FieldWriter;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.*;

public class ASMUtils {
    public static final String TYPE_UNSAFE_UTILS = JDKUtils.class.getName().replace('.', '/');

    public static final String TYPE_OBJECT_WRITER_ADAPTER
            = ObjectWriterAdapter.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_1 = ObjectWriter1.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_2 = ObjectWriter2.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_3 = ObjectWriter3.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_4 = ObjectWriter4.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_5 = ObjectWriter5.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_6 = ObjectWriter6.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_7 = ObjectWriter7.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_8 = ObjectWriter8.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_9 = ObjectWriter9.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_10 = ObjectWriter10.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_11 = ObjectWriter11.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_WRITER_12 = ObjectWriter12.class.getName().replace('.', '/');
    public static final String TYPE_FIELD_READE = FieldReader.class.getName().replace('.', '/');
    public static final String TYPE_JSON_READER = JSONReader.class.getName().replace('.', '/');

    public static final String TYPE_OBJECT_READER = ObjectReader.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_ADAPTER
            = ObjectReaderAdapter.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_1 = ObjectReader1.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_2 = ObjectReader2.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_3 = ObjectReader3.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_4 = ObjectReader4.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_5 = ObjectReader5.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_6 = ObjectReader6.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_7 = ObjectReader7.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_8 = ObjectReader8.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_9 = ObjectReader9.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_10 = ObjectReader10.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_11 = ObjectReader11.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT_READER_12 = ObjectReader12.class.getName().replace('.', '/');
    public static final String TYPE_BYTE_ARRAY_VALUE_CONSUMER = ByteArrayValueConsumer.class.getName().replace('.', '/');
    public static final String TYPE_CHAR_ARRAY_VALUE_CONSUMER = CharArrayValueConsumer.class.getName().replace('.', '/');
    public static final String TYPE_TYPE_UTILS = TypeUtils.class.getName().replace('.', '/');
    public static final String TYPE_DATE_UTILS = DateUtils.class.getName().replace('.', '/');

    public static final String TYPE_OBJECT_WRITER = ObjectWriter.class.getName().replace('.', '/');
    public static final String TYPE_JSON_WRITER = JSONWriter.class.getName().replace('.', '/');
    public static final String TYPE_FIELD_WRITER = FieldWriter.class.getName().replace('.', '/');
    public static final String TYPE_OBJECT = "java/lang/Object";

    public static final String DESC_FIELD_WRITER = 'L' + FieldWriter.class.getName().replace('.', '/') + ';';
    public static final String DESC_FIELD_WRITER_ARRAY = "[" + DESC_FIELD_WRITER;
    public static final String DESC_FIELD_READER = 'L' + FieldReader.class.getName().replace('.', '/') + ';';
    public static final String DESC_FIELD_READER_ARRAY = "[" + DESC_FIELD_READER;
    public static final String DESC_JSON_READER = 'L' + TYPE_JSON_READER + ';';
    public static final String DESC_JSON_WRITER = 'L' + TYPE_JSON_WRITER + ';';
    public static final String DESC_OBJECT_READER = 'L' + TYPE_OBJECT_READER + ';';
    public static final String DESC_OBJECT_WRITER = 'L' + TYPE_OBJECT_WRITER + ';';
    public static final String DESC_SUPPLIER = "Ljava/util/function/Supplier;";
    public static final String DESC_JSONSCHEMA = 'L' + JSONSchema.class.getName().replace('.', '/') + ';';

    static final Map paramMapping = new HashMap<>();

    static final Map descMapping = new HashMap<>();
    static final Map typeMapping = new HashMap<>();

    static {
        paramMapping.put(
                new MethodInfo(
                        ParameterizedTypeImpl.class.getName(),
                        "",
                        new String[]{"[Ljava.lang.reflect.Type;", "java.lang.reflect.Type", "java.lang.reflect.Type"}
                ),
                new String[]{"actualTypeArguments", "ownerType", "rawType"}
        );

        paramMapping.put(
                new MethodInfo(
                        "org.apache.commons.lang3.tuple.Triple",
                        "of",
                        new String[]{"java.lang.Object", "java.lang.Object", "java.lang.Object"}
                ),
                new String[]{"left", "middle", "right"}
        );
        paramMapping.put(
                new MethodInfo(
                        "org.apache.commons.lang3.tuple.MutableTriple",
                        "",
                        new String[]{"java.lang.Object", "java.lang.Object", "java.lang.Object"}
                ),
                new String[]{"left", "middle", "right"}
        );

        paramMapping.put(
                new MethodInfo(
                        "org.javamoney.moneta.Money",
                        "",
                        new String[]{"java.math.BigDecimal", "javax.money.CurrencyUnit", "javax.money.MonetaryContext"}
                ),
                new String[]{"number", "currency", "monetaryContext"}
        );
        paramMapping.put(
                new MethodInfo(
                        "org.javamoney.moneta.Money",
                        "",
                        new String[]{"java.math.BigDecimal", "javax.money.CurrencyUnit"}
                ),
                new String[]{"number", "currency"}
        );

        descMapping.put(int.class, "I");
        descMapping.put(void.class, "V");
        descMapping.put(boolean.class, "Z");
        descMapping.put(char.class, "C");
        descMapping.put(byte.class, "B");
        descMapping.put(short.class, "S");
        descMapping.put(float.class, "F");
        descMapping.put(long.class, "J");
        descMapping.put(double.class, "D");

        typeMapping.put(int.class, "I");
        typeMapping.put(void.class, "V");
        typeMapping.put(boolean.class, "Z");
        typeMapping.put(char.class, "C");
        typeMapping.put(byte.class, "B");
        typeMapping.put(short.class, "S");
        typeMapping.put(float.class, "F");
        typeMapping.put(long.class, "J");
        typeMapping.put(double.class, "D");

        Class[] classes = new Class[]{
                String.class,
                java.util.List.class,
                java.util.Collection.class,
                ObjectReader.class,
                ObjectReader1.class,
                ObjectReader2.class,
                ObjectReader3.class,
                ObjectReader4.class,
                ObjectReader5.class,
                ObjectReader6.class,
                ObjectReader7.class,
                ObjectReader8.class,
                ObjectReader9.class,
                ObjectReader10.class,
                ObjectReader11.class,
                ObjectReader12.class,
                ObjectReaderAdapter.class,
                FieldReader.class,
                JSONReader.class,
                ObjBoolConsumer.class,
                ObjCharConsumer.class,
                ObjByteConsumer.class,
                ObjShortConsumer.class,
                ObjIntConsumer.class,
                ObjLongConsumer.class,
                ObjFloatConsumer.class,
                ObjDoubleConsumer.class,
                BiConsumer.class,
                JDKUtils.class,
                ObjectWriterAdapter.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,
                com.alibaba.fastjson2.writer.FieldWriter.class,
                JSONPathCompilerReflect.SingleNamePathTyped.class,
                JSONWriter.Context.class,
                JSONB.class,
                JSONSchema.class,
                JSONType.class,
                java.util.Date.class,
                java.util.function.Supplier.class
        };
        for (Class objectType : classes) {
            String type = objectType.getName().replace('.', '/');
            typeMapping.put(objectType, type);
            String desc = 'L' + type + ';';
            descMapping.put(objectType, desc);
        }

        typeMapping.put(JSONWriter.class, TYPE_JSON_WRITER);
        descMapping.put(JSONWriter.class, DESC_JSON_WRITER);
        typeMapping.put(ObjectWriter.class, TYPE_OBJECT_WRITER);
        descMapping.put(ObjectWriter.class, DESC_OBJECT_WRITER);

        descMapping.put(FieldWriter[].class, DESC_FIELD_WRITER_ARRAY);
        descMapping.put(FieldReader[].class, DESC_FIELD_READER_ARRAY);
    }

    public static String type(Class clazz) {
        String type = typeMapping.get(clazz);
        if (type != null) {
            return type;
        }

        if (clazz.isArray()) {
            return "[" + desc(clazz.getComponentType());
        }

        // 直接基于字符串替换,不使用正则替换
        return clazz.getName().replace('.', '/');
    }

    static final AtomicReference descCacheRef = new AtomicReference<>();

    public static String desc(Class clazz) {
        String desc = descMapping.get(clazz);
        if (desc != null) {
            return desc;
        }

        if (clazz.isArray()) {
            Class componentType = clazz.getComponentType();
            return "[" + desc(componentType);
        }

        String className = clazz.getName();
        char[] chars = descCacheRef.getAndSet(null);
        if (chars == null) {
            chars = new char[512];
        }
        chars[0] = 'L';
        className.getChars(0, className.length(), chars, 1);
        for (int i = 1; i < chars.length; i++) {
            if (chars[i] == '.') {
                chars[i] = '/';
            }
        }
        chars[className.length() + 1] = ';';

        String str = new String(chars, 0, className.length() + 2);
        descCacheRef.compareAndSet(null, chars);
        return str;
    }

    public static String[] lookupParameterNames(AccessibleObject methodOrCtor) {
        if (methodOrCtor instanceof Constructor) {
            Constructor constructor = (Constructor) methodOrCtor;
            Class[] parameterTypes = constructor.getParameterTypes();

            Class declaringClass = constructor.getDeclaringClass();
            if (declaringClass == DateTimeParseException.class) {
                if (parameterTypes.length == 3) {
                    if (parameterTypes[0] == String.class && parameterTypes[1] == CharSequence.class && parameterTypes[2] == int.class) {
                        return new String[]{"message", "parsedString", "errorIndex"};
                    }
                } else if (parameterTypes.length == 4) {
                    if (parameterTypes[0] == String.class && parameterTypes[1] == CharSequence.class && parameterTypes[2] == int.class && parameterTypes[3] == Throwable.class) {
                        return new String[]{"message", "parsedString", "errorIndex", "cause"};
                    }
                }
            }

            if (Throwable.class.isAssignableFrom(declaringClass)) {
                switch (parameterTypes.length) {
                    case 1:
                        if (parameterTypes[0] == String.class) {
                            return new String[]{"message"};
                        }

                        if (Throwable.class.isAssignableFrom(parameterTypes[0])) {
                            return new String[]{"cause"};
                        }
                        break;
                    case 2:
                        if (parameterTypes[0] == String.class && Throwable.class.isAssignableFrom(parameterTypes[1])) {
                            return new String[]{"message", "cause"};
                        }
                        break;
                    default:
                        break;
                }
            }
        }

        final Class[] types;
        final Class declaringClass;
        final String name;

        int paramCount;
        if (methodOrCtor instanceof Method) {
            Method method = (Method) methodOrCtor;
            types = method.getParameterTypes();
            name = method.getName();
            declaringClass = method.getDeclaringClass();
            paramCount = method.getParameterCount();
        } else {
            Constructor constructor = (Constructor) methodOrCtor;
            types = constructor.getParameterTypes();
            declaringClass = constructor.getDeclaringClass();
            name = "";
            paramCount = constructor.getParameterCount();
        }

        if (types.length == 0) {
            return new String[paramCount];
        }

        String[] paramNames = paramMapping.get(new MethodInfo(declaringClass.getName(), name, types));
        if (paramNames != null) {
            return paramNames;
        }

        ClassLoader classLoader = declaringClass.getClassLoader();
        if (classLoader == null) {
            classLoader = ClassLoader.getSystemClassLoader();
        }

        String className = declaringClass.getName();
        String resourceName = className.replace('.', '/') + ".class";
        InputStream is = classLoader.getResourceAsStream(resourceName);

        if (is != null) {
            try {
                ClassReader reader = new ClassReader(is);
                TypeCollector visitor = new TypeCollector(name, types);
                reader.accept(visitor);

                paramNames = visitor.getParameterNamesForMethod();
                if (paramNames != null && paramNames.length == paramCount - 1) {
                    Class dd = declaringClass.getDeclaringClass();
                    if (dd != null && dd.equals(types[0])) {
                        String[] strings = new String[paramCount];
                        strings[0] = "this$0";
                        System.arraycopy(paramNames, 0, strings, 1, paramNames.length);
                        paramNames = strings;
                    }
                }
                return paramNames;
            } catch (IOException | ArrayIndexOutOfBoundsException ignored) {
                // ignored
            } finally {
                IOUtils.close(is);
            }
        }

        paramNames = new String[paramCount];
        int i;
        if (types[0] == declaringClass.getDeclaringClass()
                && !Modifier.isStatic(declaringClass.getModifiers())) {
            paramNames[0] = "this.$0";
            i = 1;
        } else {
            i = 0;
        }
        for (; i < paramNames.length; i++) {
            paramNames[i] = "arg" + i;
        }
        return paramNames;
    }

    static final class MethodInfo {
        final String className;
        final String methodName;
        final String[] paramTypeNames;
        int hash;

        public MethodInfo(String className, String methodName, String[] paramTypeNames) {
            this.className = className;
            this.methodName = methodName;
            this.paramTypeNames = paramTypeNames;
        }

        public MethodInfo(String className, String methodName, Class[] paramTypes) {
            this.className = className;
            this.methodName = methodName;
            this.paramTypeNames = new String[paramTypes.length];
            for (int i = 0; i < paramTypes.length; i++) {
                paramTypeNames[i] = paramTypes[i].getName();
            }
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            MethodInfo that = (MethodInfo) o;
            return Objects.equals(className, that.className) && Objects.equals(methodName, that.methodName) && Arrays.equals(paramTypeNames, that.paramTypeNames);
        }

        @Override
        public int hashCode() {
            if (hash == 0) {
                int result = Objects.hash(className, methodName);
                result = 31 * result + Arrays.hashCode(paramTypeNames);
                hash = result;
            }
            return hash;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy