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

com.alibaba.fastjson2.reader.ObjectReaderBaseModule 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.*;
import com.alibaba.fastjson2.annotation.*;
import com.alibaba.fastjson2.codec.BeanInfo;
import com.alibaba.fastjson2.codec.FieldInfo;
import com.alibaba.fastjson2.function.impl.*;
import com.alibaba.fastjson2.modules.ObjectReaderAnnotationProcessor;
import com.alibaba.fastjson2.modules.ObjectReaderModule;
import com.alibaba.fastjson2.support.LambdaMiscCodec;
import com.alibaba.fastjson2.support.money.MoneySupport;
import com.alibaba.fastjson2.util.*;

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.function.Function;
import java.util.regex.Pattern;

import static com.alibaba.fastjson2.util.BeanUtils.*;

public class ObjectReaderBaseModule
        implements ObjectReaderModule {
    final ObjectReaderProvider provider;
    final ReaderAnnotationProcessor annotationProcessor;

    public ObjectReaderBaseModule(ObjectReaderProvider provider) {
        this.provider = provider;
        this.annotationProcessor = new ReaderAnnotationProcessor();
    }

    @Override
    public ObjectReaderProvider getProvider() {
        return provider;
    }

    @Override
    public void init(ObjectReaderProvider provider) {
        provider.registerTypeConvert(Character.class, char.class, o -> o);

        Class[] numberTypes = new Class[]{
                Boolean.class,
                Byte.class,
                Short.class,
                Integer.class,
                Long.class,
                Number.class,
                Float.class,
                Double.class,
                BigInteger.class,
                BigDecimal.class,
                AtomicInteger.class,
                AtomicLong.class,
        };

        Function TO_BOOLEAN = new ToBoolean(null);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, Boolean.class, TO_BOOLEAN);
        }

        Function TO_BOOLEAN_VALUE = new ToBoolean(Boolean.FALSE);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, boolean.class, TO_BOOLEAN_VALUE);
        }

        Function TO_STRING = new ToString();
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, String.class, TO_STRING);
        }

        Function TO_DECIMAL = new ToBigDecimal();
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, BigDecimal.class, TO_DECIMAL);
        }

        Function TO_BIGINT = new ToBigInteger();
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, BigInteger.class, TO_BIGINT);
        }

        Function TO_BYTE = new ToByte(null);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, Byte.class, TO_BYTE);
        }

        Function TO_BYTE_VALUE = new ToByte((byte) 0);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, byte.class, TO_BYTE_VALUE);
        }

        Function TO_SHORT = new ToShort(null);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, Short.class, TO_SHORT);
        }

        Function TO_SHORT_VALUE = new ToShort((short) 0);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, short.class, TO_SHORT_VALUE);
        }

        Function TO_INTEGER = new ToInteger(null);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, Integer.class, TO_INTEGER);
        }

        Function TO_INT = new ToInteger(0);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, int.class, TO_INT);
        }

        Function TO_LONG = new ToLong(null);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, Long.class, TO_LONG);
        }

        Function TO_LONG_VALUE = new ToLong(0L);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, long.class, TO_LONG_VALUE);
        }

        Function TO_FLOAT = new ToFloat(null);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, Float.class, TO_FLOAT);
        }

        Function TO_FLOAT_VALUE = new ToFloat(0F);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, float.class, TO_FLOAT_VALUE);
        }

        Function TO_DOUBLE = new ToDouble(null);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, Double.class, TO_DOUBLE);
        }

        Function TO_DOUBLE_VALUE = new ToDouble(0D);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, double.class, TO_DOUBLE_VALUE);
        }

        Function TO_NUMBER = new ToNumber(0D);
        for (Class type : numberTypes) {
            provider.registerTypeConvert(type, Number.class, TO_NUMBER);
        }

        {
            // String to Any
            provider.registerTypeConvert(String.class, char.class, new StringToAny(char.class, '0'));
            provider.registerTypeConvert(String.class, boolean.class, new StringToAny(boolean.class, false));
            provider.registerTypeConvert(String.class, float.class, new StringToAny(float.class, (float) 0));
            provider.registerTypeConvert(String.class, double.class, new StringToAny(double.class, (double) 0));
            provider.registerTypeConvert(String.class, byte.class, new StringToAny(byte.class, (byte) 0));
            provider.registerTypeConvert(String.class, short.class, new StringToAny(short.class, (short) 0));
            provider.registerTypeConvert(String.class, int.class, new StringToAny(int.class, 0));
            provider.registerTypeConvert(String.class, long.class, new StringToAny(long.class, 0L));

            provider.registerTypeConvert(String.class, Character.class, new StringToAny(Character.class, null));
            provider.registerTypeConvert(String.class, Boolean.class, new StringToAny(Boolean.class, null));
            provider.registerTypeConvert(String.class, Double.class, new StringToAny(Double.class, null));
            provider.registerTypeConvert(String.class, Float.class, new StringToAny(Float.class, null));
            provider.registerTypeConvert(String.class, Byte.class, new StringToAny(Byte.class, null));
            provider.registerTypeConvert(String.class, Short.class, new StringToAny(Short.class, null));
            provider.registerTypeConvert(String.class, Integer.class, new StringToAny(Integer.class, null));
            provider.registerTypeConvert(String.class, Long.class, new StringToAny(Long.class, null));
            provider.registerTypeConvert(String.class, BigDecimal.class, new StringToAny(BigDecimal.class, null));
            provider.registerTypeConvert(String.class, BigInteger.class, new StringToAny(BigInteger.class, null));
            provider.registerTypeConvert(String.class, Number.class, new StringToAny(BigDecimal.class, null));
            provider.registerTypeConvert(String.class, Collection.class, new StringToAny(Collection.class, null));
            provider.registerTypeConvert(String.class, List.class, new StringToAny(List.class, null));
            provider.registerTypeConvert(String.class, JSONArray.class, new StringToAny(JSONArray.class, null));
        }

        {
            provider.registerTypeConvert(Boolean.class, boolean.class, o -> o);
        }
        {
            Function function = o -> o == null || "null".equals(o) || o.equals(0L)
                    ? null
                    : LocalDateTime.ofInstant(Instant.ofEpochMilli((Long) o), ZoneId.systemDefault());
            provider.registerTypeConvert(Long.class, LocalDateTime.class, function);
        }
        {
            Function function = o -> o == null || "null".equals(o) || "".equals(o)
                    ? null
                    : UUID.fromString((String) o);
            provider.registerTypeConvert(String.class, UUID.class, function);
        }
    }

    public class ReaderAnnotationProcessor
            implements ObjectReaderAnnotationProcessor {
        @Override
        public void getBeanInfo(BeanInfo beanInfo, Class objectClass) {
            Class mixInSource = provider.mixInCache.get(objectClass);
            if (mixInSource == null) {
                String typeName = objectClass.getName();
                if ("org.apache.commons.lang3.tuple.Triple".equals(typeName)) {
                    provider.mixIn(objectClass, mixInSource = ApacheLang3Support.TripleMixIn.class);
                }
            }

            if (mixInSource != null && mixInSource != objectClass) {
                beanInfo.mixIn = true;
                getBeanInfo(beanInfo, getAnnotations(mixInSource));

                BeanUtils.staticMethod(mixInSource,
                        method -> getCreator(beanInfo, objectClass, method)
                );

                BeanUtils.constructor(mixInSource, constructor ->
                        getCreator(beanInfo, objectClass, constructor)
                );
            }

            Class seeAlsoClass = null;
            for (Class superClass = objectClass.getSuperclass(); ; superClass = superClass.getSuperclass()) {
                if (superClass == null || superClass == Object.class || superClass == Enum.class) {
                    break;
                }

                BeanInfo superBeanInfo = new BeanInfo(JSONFactory.getDefaultObjectReaderProvider());
                getBeanInfo(superBeanInfo, superClass);
                if (superBeanInfo.seeAlso != null) {
                    boolean inSeeAlso = false;
                    for (Class seeAlsoItem : superBeanInfo.seeAlso) {
                        if (seeAlsoItem == objectClass) {
                            inSeeAlso = true;
                            break;
                        }
                    }
                    if (!inSeeAlso) {
                        seeAlsoClass = superClass;
                    }
                }
            }

            if (seeAlsoClass != null) {
                getBeanInfo(beanInfo, seeAlsoClass);
            }

            Annotation[] annotations = getAnnotations(objectClass);
            getBeanInfo(beanInfo, annotations);

            for (Annotation annotation : annotations) {
                boolean useJacksonAnnotation = JSONFactory.isUseJacksonAnnotation();
                Class annotationType = annotation.annotationType();
                String annotationTypeName = annotationType.getName();
                switch (annotationTypeName) {
                    case "com.alibaba.fastjson.annotation.JSONType":
                        getBeanInfo1x(beanInfo, annotation);
                        break;
                    case "com.fasterxml.jackson.annotation.JsonTypeInfo":
                        if (useJacksonAnnotation) {
                            processJacksonJsonTypeInfo(beanInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.databind.annotation.JsonDeserialize":
                        if (useJacksonAnnotation) {
                            processJacksonJsonDeserializer(beanInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonTypeName":
                        if (useJacksonAnnotation) {
                            processJacksonJsonTypeName(beanInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonFormat":
                        if (useJacksonAnnotation) {
                            processJacksonJsonFormat(beanInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonInclude":
                        if (useJacksonAnnotation) {
                            processJacksonJsonInclude(beanInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonSubTypes":
                        if (useJacksonAnnotation) {
                            processJacksonJsonSubTypes(beanInfo, annotation);
                        }
                        break;
                    case "kotlin.Metadata":
                        beanInfo.kotlin = true;
                        break;
                    default:
                        break;
                }
            }

            BeanUtils.staticMethod(objectClass,
                    method -> getCreator(beanInfo, objectClass, method)
            );

            BeanUtils.constructor(objectClass, constructor ->
                    getCreator(beanInfo, objectClass, constructor)
            );

            if (beanInfo.creatorConstructor == null
                    && (beanInfo.readerFeatures & JSONReader.Feature.FieldBased.mask) == 0
                    && beanInfo.kotlin) {
                KotlinUtils.getConstructor(objectClass, beanInfo);
            }
        }

        private void processJacksonJsonSubTypes(BeanInfo beanInfo, Annotation annotation) {
            Class annotationClass = annotation.getClass();
            BeanUtils.annotationMethods(annotationClass, m -> {
                String name = m.getName();
                try {
                    Object result = m.invoke(annotation);
                    if ("value".equals(name)) {
                        Object[] value = (Object[]) result;
                        if (value.length != 0) {
                            beanInfo.seeAlso = new Class[value.length];
                            beanInfo.seeAlsoNames = new String[value.length];
                            for (int i = 0; i < value.length; i++) {
                                Annotation subTypeAnn = (Annotation) value[i];
                                processJacksonJsonSubTypesType(beanInfo, i, subTypeAnn);
                            }
                        }
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void processJacksonJsonDeserializer(BeanInfo beanInfo, Annotation annotation) {
            Class annotationClass = annotation.getClass();
            BeanUtils.annotationMethods(annotationClass, m -> {
                String name = m.getName();
                try {
                    Object result = m.invoke(annotation);
                    if ("using".equals(name) || "contentUsing".equals(name)) {
                        Class using = processUsing((Class) result);
                        if (using != null) {
                            beanInfo.deserializer = using;
                        }
                    } else if ("builder".equals(name)) {
                        processBuilder(beanInfo, (Class) result);
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void processJacksonJsonTypeInfo(BeanInfo beanInfo, Annotation annotation) {
            Class annotationClass = annotation.getClass();
            BeanUtils.annotationMethods(annotationClass, m -> {
                String name = m.getName();
                try {
                    Object result = m.invoke(annotation);
                    if ("property".equals(name)) {
                        String value = (String) result;
                        if (!value.isEmpty()) {
                            beanInfo.typeKey = value;
                            beanInfo.readerFeatures |= JSONReader.Feature.SupportAutoType.mask;
                        }
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void getBeanInfo(BeanInfo beanInfo, Annotation[] annotations) {
            for (Annotation annotation : annotations) {
                Class annotationType = annotation.annotationType();
                JSONType jsonType = findAnnotation(annotation, JSONType.class);
                if (jsonType != null) {
                    getBeanInfo1x(beanInfo, annotation);
                    if (jsonType == annotation) {
                        continue;
                    }
                }

                if (annotationType == JSONCompiler.class) {
                    JSONCompiler compiler = (JSONCompiler) annotation;
                    if (compiler.value() == JSONCompiler.CompilerOption.LAMBDA) {
                        beanInfo.readerFeatures |= FieldInfo.JIT;
                    }
                }
            }
        }

        void getBeanInfo1x(BeanInfo beanInfo, Annotation annotation) {
            Class annotationClass = annotation.getClass();
            BeanUtils.annotationMethods(annotationClass, m -> {
                String name = m.getName();
                try {
                    Object result = m.invoke(annotation);

                    switch (name) {
                        case "seeAlso": {
                            Class[] classes = (Class[]) result;
                            if (classes.length != 0) {
                                beanInfo.seeAlso = classes;
                                beanInfo.seeAlsoNames = new String[classes.length];
                                for (int i = 0; i < classes.length; i++) {
                                    Class item = classes[i];

                                    BeanInfo itemBeanInfo = new BeanInfo(JSONFactory.getDefaultObjectReaderProvider());
                                    processSeeAlsoAnnotation(itemBeanInfo, item);
                                    String typeName = itemBeanInfo.typeName;
                                    if (typeName == null || typeName.isEmpty()) {
                                        typeName = item.getSimpleName();
                                    }
                                    beanInfo.seeAlsoNames[i] = typeName;
                                }
                                beanInfo.readerFeatures |= JSONReader.Feature.SupportAutoType.mask;
                            }
                            break;
                        }
                        case "seeAlsoDefault": {
                            Class seeAlsoDefault = (Class) result;
                            if (seeAlsoDefault != Void.class) {
                                beanInfo.seeAlsoDefault = seeAlsoDefault;
                            }
                        }
                        case "typeKey": {
                            String jsonTypeKey = (String) result;
                            if (!jsonTypeKey.isEmpty()) {
                                beanInfo.typeKey = jsonTypeKey;
                            }
                            break;
                        }
                        case "typeName": {
                            String typeName = (String) result;
                            if (!typeName.isEmpty()) {
                                beanInfo.typeName = typeName;
                            }
                            break;
                        }
                        case "rootName": {
                            String rootName = (String) result;
                            if (!rootName.isEmpty()) {
                                beanInfo.rootName = rootName;
                            }
                            break;
                        }
                        case "naming": {
                            Enum naming = (Enum) result;
                            beanInfo.namingStrategy = naming.name();
                            break;
                        }
                        case "ignores": {
                            String[] ignores = (String[]) result;
                            if (ignores.length > 0) {
                                beanInfo.ignores = ignores;
                            }
                            break;
                        }
                        case "orders": {
                            String[] fields = (String[]) result;
                            if (fields.length != 0) {
                                beanInfo.orders = fields;
                            }
                            break;
                        }
                        case "schema": {
                            String schema = (String) result;
                            schema = schema.trim();
                            if (!schema.isEmpty()) {
                                beanInfo.schema = schema;
                            }
                            break;
                        }
                        case "deserializer": {
                            Class deserializer = (Class) result;
                            if (ObjectReader.class.isAssignableFrom(deserializer)) {
                                beanInfo.deserializer = deserializer;
                            }
                            break;
                        }
                        case "parseFeatures": {
                            Enum[] features = (Enum[]) result;
                            for (Enum feature : features) {
                                switch (feature.name()) {
                                    case "SupportAutoType":
                                        beanInfo.readerFeatures |= JSONReader.Feature.SupportAutoType.mask;
                                        break;
                                    case "SupportArrayToBean":
                                        beanInfo.readerFeatures |= JSONReader.Feature.SupportArrayToBean.mask;
                                        break;
                                    case "InitStringFieldAsEmpty":
                                        beanInfo.readerFeatures |= JSONReader.Feature.InitStringFieldAsEmpty.mask;
                                        break;
                                    case "TrimStringFieldValue":
//                                        beanInfo.readerFeatures |= JSONReader.Feature.TrimStringFieldValue.mask;
                                        break;
                                    default:
                                        break;
                                }
                            }
                            break;
                        }
                        case "deserializeFeatures": {
                            JSONReader.Feature[] features = (JSONReader.Feature[]) result;
                            for (JSONReader.Feature feature : features) {
                                beanInfo.readerFeatures |= feature.mask;
                            }
                            break;
                        }
                        case "builder": {
                            processBuilder(beanInfo, (Class) result);
                            break;
                        }
                        case "deserializeUsing": {
                            Class deserializeUsing = (Class) result;
                            if (ObjectReader.class.isAssignableFrom(deserializeUsing)) {
                                beanInfo.deserializer = deserializeUsing;
                            }
                            break;
                        }
                        case "autoTypeBeforeHandler":
                        case "autoTypeCheckHandler": {
                            Class autoTypeCheckHandler = (Class) result;
                            if (autoTypeCheckHandler != JSONReader.AutoTypeBeforeHandler.class
                                    && JSONReader.AutoTypeBeforeHandler.class.isAssignableFrom(autoTypeCheckHandler)) {
                                beanInfo.autoTypeBeforeHandler = (Class) autoTypeCheckHandler;
                            }
                            break;
                        }
                        case "disableReferenceDetect":
                            if (Boolean.TRUE.equals(result)) {
                                beanInfo.readerFeatures |= FieldInfo.DISABLE_REFERENCE_DETECT;
                            }
                            break;
                        case "disableArrayMapping":
                            if (Boolean.TRUE.equals(result)) {
                                beanInfo.readerFeatures |= FieldInfo.DISABLE_ARRAY_MAPPING;
                            }
                            break;
                        case "disableAutoType":
                            if (Boolean.TRUE.equals(result)) {
                                beanInfo.readerFeatures |= FieldInfo.DISABLE_AUTO_TYPE;
                            }
                            break;
                        case "disableJSONB":
                            if (Boolean.TRUE.equals(result)) {
                                beanInfo.readerFeatures |= FieldInfo.DISABLE_JSONB;
                            }
                            break;
                        default:
                            break;
                    }
                } catch (Throwable ignored) {
                }
            });
        }

        private void processBuilder(BeanInfo beanInfo, Class result) {
            Class builderClass = result;
            if (builderClass != void.class && builderClass != Void.class) {
                beanInfo.builder = builderClass;

                for (Annotation builderAnnotation : getAnnotations(builderClass)) {
                    Class builderAnnotationClass = builderAnnotation.annotationType();
                    String builderAnnotationName = builderAnnotationClass.getName();

                    if ("com.alibaba.fastjson.annotation.JSONPOJOBuilder".equals(builderAnnotationName)
                            || "com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder".equals(builderAnnotationName)) {
                        getBeanInfo1xJSONPOJOBuilder(beanInfo, builderClass, builderAnnotation, builderAnnotationClass);
                    } else {
                        JSONBuilder jsonBuilder = findAnnotation(builderClass, JSONBuilder.class);
                        if (jsonBuilder != null) {
                            String buildMethodName = jsonBuilder.buildMethod();
                            beanInfo.buildMethod = buildMethod(builderClass, buildMethodName);
                            String withPrefix = jsonBuilder.withPrefix();
                            if (!withPrefix.isEmpty()) {
                                beanInfo.builderWithPrefix = withPrefix;
                            }
                        }
                    }
                }

                if (beanInfo.buildMethod == null) {
                    beanInfo.buildMethod = BeanUtils.buildMethod(builderClass, "build");
                }

                if (beanInfo.buildMethod == null) {
                    beanInfo.buildMethod = BeanUtils.buildMethod(builderClass, "create");
                }
            }
        }

        private void processSeeAlsoAnnotation(BeanInfo beanInfo, Class objectClass) {
            Class mixInSource = provider.mixInCache.get(objectClass);
            if (mixInSource == null) {
                String typeName = objectClass.getName();
                if ("org.apache.commons.lang3.tuple.Triple".equals(typeName)) {
                    provider.mixIn(objectClass, mixInSource = ApacheLang3Support.TripleMixIn.class);
                }
            }

            if (mixInSource != null && mixInSource != objectClass) {
                beanInfo.mixIn = true;
                processSeeAlsoAnnotation(beanInfo, getAnnotations(mixInSource));
            }

            processSeeAlsoAnnotation(beanInfo, getAnnotations(objectClass));
        }

        private void processSeeAlsoAnnotation(BeanInfo beanInfo, Annotation[] annotations) {
            for (Annotation annotation : annotations) {
                Class itemAnnotationType = annotation.annotationType();
                BeanUtils.annotationMethods(itemAnnotationType, m -> {
                    String name = m.getName();
                    try {
                        Object result = m.invoke(annotation);
                        if ("typeName".equals(name)) {
                            String typeName = (String) result;
                            if (!typeName.isEmpty()) {
                                beanInfo.typeName = typeName;
                            }
                        }
                    } catch (Throwable ignored) {
                        // ignored
                    }
                });
            }
        }

        @Override
        public void getFieldInfo(
                FieldInfo fieldInfo,
                Class objectClass,
                Constructor constructor,
                int paramIndex,
                Parameter parameter
        ) {
            if (objectClass != null) {
                Class mixInSource = provider.mixInCache.get(objectClass);
                if (mixInSource != null && mixInSource != objectClass) {
                    Constructor mixInConstructor = null;
                    try {
                        mixInConstructor = mixInSource.getDeclaredConstructor(constructor.getParameterTypes());
                    } catch (NoSuchMethodException ignored) {
                    }
                    if (mixInConstructor != null) {
                        Parameter mixInParam = mixInConstructor.getParameters()[paramIndex];
                        processAnnotation(fieldInfo, getAnnotations(mixInParam));
                    }
                }
            }

            boolean staticClass = Modifier.isStatic(constructor.getDeclaringClass().getModifiers());
            Annotation[] annotations = null;
            if (staticClass) {
                try {
                    annotations = getAnnotations(parameter);
                } catch (ArrayIndexOutOfBoundsException ignored) {
                    // ignored
                }
            } else {
                Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
                int paIndex;
                if (parameterAnnotations.length == constructor.getParameterCount()) {
                    paIndex = paramIndex;
                } else {
                    paIndex = paramIndex - 1;
                }
                if (paIndex >= 0 && paIndex < parameterAnnotations.length) {
                    annotations = parameterAnnotations[paIndex];
                }
            }

            if (annotations != null && annotations.length > 0) {
                processAnnotation(fieldInfo, annotations);
            }
        }

        @Override
        public void getFieldInfo(
                FieldInfo fieldInfo,
                Class objectClass,
                Method method,
                int paramIndex,
                Parameter parameter
        ) {
            if (objectClass != null) {
                Class mixInSource = provider.mixInCache.get(objectClass);
                if (mixInSource != null && mixInSource != objectClass) {
                    Method mixInMethod = null;
                    try {
                        mixInMethod = mixInSource.getMethod(method.getName(), method.getParameterTypes());
                    } catch (NoSuchMethodException ignored) {
                    }
                    if (mixInMethod != null) {
                        Parameter mixInParam = mixInMethod.getParameters()[paramIndex];
                        processAnnotation(fieldInfo, getAnnotations(mixInParam));
                    }
                }
            }

            processAnnotation(fieldInfo, getAnnotations(parameter));
        }

        @Override
        public void getFieldInfo(FieldInfo fieldInfo, Class objectClass, Field field) {
            if (objectClass != null) {
                Class mixInSource = provider.mixInCache.get(objectClass);
                if (mixInSource != null && mixInSource != objectClass) {
                    Field mixInField = null;
                    try {
                        mixInField = mixInSource.getDeclaredField(field.getName());
                    } catch (Exception ignored) {
                    }

                    if (mixInField != null) {
                        getFieldInfo(fieldInfo, mixInSource, mixInField);
                    }
                }
            }

            Annotation[] annotations = getAnnotations(field);
            processAnnotation(fieldInfo, annotations);
        }

        @Override
        public void getFieldInfo(FieldInfo fieldInfo, Class objectClass, Method method) {
            String methodName = method.getName();

            if (objectClass != null) {
                Class superclass = objectClass.getSuperclass();
                Method supperMethod = BeanUtils.getMethod(superclass, method);
                if (supperMethod != null) {
                    getFieldInfo(fieldInfo, superclass, supperMethod);
                }

                Class[] interfaces = objectClass.getInterfaces();
                for (Class i : interfaces) {
                    if (i == Serializable.class) {
                        continue;
                    }

                    Method interfaceMethod = BeanUtils.getMethod(i, method);
                    if (interfaceMethod != null) {
                        getFieldInfo(fieldInfo, superclass, interfaceMethod);
                    }
                }

                Class mixInSource = provider.mixInCache.get(objectClass);
                if (mixInSource != null && mixInSource != objectClass) {
                    Method mixInMethod = null;
                    try {
                        mixInMethod = mixInSource.getDeclaredMethod(methodName, method.getParameterTypes());
                    } catch (Exception ignored) {
                    }

                    if (mixInMethod != null) {
                        getFieldInfo(fieldInfo, mixInSource, mixInMethod);
                    }
                }
            }

            String jsonFieldName = null;

            Annotation[] annotations = getAnnotations(method);
            for (Annotation annotation : annotations) {
                Class annotationType = annotation.annotationType();
                JSONField jsonField = findAnnotation(annotation, JSONField.class);
                if (jsonField != null) {
                    getFieldInfo(fieldInfo, jsonField);
                    jsonFieldName = jsonField.name();
                    if (jsonField == annotation) {
                        continue;
                    }
                }

                if (annotationType == JSONCompiler.class) {
                    JSONCompiler compiler = (JSONCompiler) annotation;
                    if (compiler.value() == JSONCompiler.CompilerOption.LAMBDA) {
                        fieldInfo.features |= FieldInfo.JIT;
                    }
                }

                boolean useJacksonAnnotation = JSONFactory.isUseJacksonAnnotation();
                String annotationTypeName = annotationType.getName();
                switch (annotationTypeName) {
                    case "com.fasterxml.jackson.annotation.JsonIgnore":
                        if (useJacksonAnnotation) {
                            processJacksonJsonIgnore(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.databind.annotation.JsonDeserialize":
                        if (useJacksonAnnotation) {
                            processJacksonJsonDeserialize(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonFormat":
                        if (useJacksonAnnotation) {
                            processJacksonJsonFormat(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonAnySetter":
                        if (useJacksonAnnotation) {
                            fieldInfo.features |= FieldInfo.UNWRAPPED_MASK;
                        }
                        break;
                    case "com.alibaba.fastjson.annotation.JSONField":
                        processJSONField1x(fieldInfo, annotation);
                        break;
                    case "com.fasterxml.jackson.annotation.JsonProperty":
                        if (useJacksonAnnotation) {
                            processJacksonJsonProperty(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonAlias":
                        if (useJacksonAnnotation) {
                            processJacksonJsonAlias(fieldInfo, annotation);
                        }
                        break;
                    case "com.google.gson.annotations.SerializedName":
                        if (JSONFactory.isUseGsonAnnotation()) {
                            processGsonSerializedName(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonInclude":
                        if (useJacksonAnnotation) {
                            processJacksonJsonInclude(fieldInfo, annotation);
                        }
                        break;
                    default:
                        break;
                }
            }

            String fieldName;
            if (methodName.startsWith("set")) {
                fieldName = BeanUtils.setterName(methodName, null);
            } else {
                fieldName = BeanUtils.getterName(methodName, null); // readOnlyProperty
            }

            String fieldName1, fieldName2;
            char c0, c1;
            if (fieldName.length() > 1
                    && (c0 = fieldName.charAt(0)) >= 'A' && c0 <= 'Z'
                    && (c1 = fieldName.charAt(1)) >= 'A' && c1 <= 'Z'
                    && (jsonFieldName == null || jsonFieldName.isEmpty())) {
                char[] chars = fieldName.toCharArray();
                chars[0] = (char) (chars[0] + 32);
                fieldName1 = new String(chars);

                chars[1] = (char) (chars[1] + 32);
                fieldName2 = new String(chars);
            } else {
                fieldName1 = null;
                fieldName2 = null;
            }

            BeanUtils.declaredFields(objectClass, field -> {
                if (field.getName().equals(fieldName)) {
                    int modifiers = field.getModifiers();
                    if ((!Modifier.isPublic(modifiers)) && !Modifier.isStatic(modifiers)) {
                        getFieldInfo(fieldInfo, objectClass, field);
                    }
                    fieldInfo.features |= FieldInfo.FIELD_MASK;
                } else if (field.getName().equals(fieldName1)) {
                    int modifiers = field.getModifiers();
                    if ((!Modifier.isPublic(modifiers)) && !Modifier.isStatic(modifiers)) {
                        getFieldInfo(fieldInfo, objectClass, field);
                    }
                    fieldInfo.features |= FieldInfo.FIELD_MASK;
                } else if (field.getName().equals(fieldName2)) {
                    int modifiers = field.getModifiers();
                    if ((!Modifier.isPublic(modifiers)) && !Modifier.isStatic(modifiers)) {
                        getFieldInfo(fieldInfo, objectClass, field);
                    }
                    fieldInfo.features |= FieldInfo.FIELD_MASK;
                }
            });

            if (fieldName1 != null && fieldInfo.fieldName == null && fieldInfo.alternateNames == null) {
                fieldInfo.alternateNames = new String[]{fieldName1, fieldName2};
            }
        }

        private void processAnnotation(FieldInfo fieldInfo, Annotation[] annotations) {
            for (Annotation annotation : annotations) {
                Class annotationType = annotation.annotationType();
                JSONField jsonField = findAnnotation(annotation, JSONField.class);
                if (jsonField != null) {
                    getFieldInfo(fieldInfo, jsonField);
                    if (jsonField == annotation) {
                        continue;
                    }
                }

                if (annotationType == JSONCompiler.class) {
                    JSONCompiler compiler = (JSONCompiler) annotation;
                    if (compiler.value() == JSONCompiler.CompilerOption.LAMBDA) {
                        fieldInfo.features |= FieldInfo.JIT;
                    }
                }

                boolean useJacksonAnnotation = JSONFactory.isUseJacksonAnnotation();
                String annotationTypeName = annotationType.getName();
                switch (annotationTypeName) {
                    case "com.fasterxml.jackson.annotation.JsonIgnore":
                        if (useJacksonAnnotation) {
                            processJacksonJsonIgnore(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonAnyGetter":
                        if (useJacksonAnnotation) {
                            fieldInfo.features |= FieldInfo.UNWRAPPED_MASK;
                        }
                        break;
                    case "com.alibaba.fastjson.annotation.JSONField":
                        processJSONField1x(fieldInfo, annotation);
                        break;
                    case "com.fasterxml.jackson.annotation.JsonProperty":
                        if (useJacksonAnnotation) {
                            processJacksonJsonProperty(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonFormat":
                        if (useJacksonAnnotation) {
                            processJacksonJsonFormat(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.databind.annotation.JsonDeserialize":
                        if (useJacksonAnnotation) {
                            processJacksonJsonDeserialize(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonAlias":
                        if (useJacksonAnnotation) {
                            processJacksonJsonAlias(fieldInfo, annotation);
                        }
                        break;
                    case "com.google.gson.annotations.SerializedName":
                        if (JSONFactory.isUseGsonAnnotation()) {
                            processGsonSerializedName(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonSetter":
                        if (useJacksonAnnotation) {
                            processJacksonJsonSetter(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonManagedReference":
                        if (useJacksonAnnotation) {
                            fieldInfo.features |= JSONWriter.Feature.ReferenceDetection.mask;
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonBackReference":
                        if (useJacksonAnnotation) {
                            fieldInfo.features |= FieldInfo.BACKR_EFERENCE;
                        }
                        break;
                    default:
                        break;
                }
            }
        }

        private void processJacksonJsonDeserialize(FieldInfo fieldInfo, Annotation annotation) {
            if (!JSONFactory.isUseJacksonAnnotation()) {
                return;
            }

            Class annotationClass = annotation.getClass();
            BeanUtils.annotationMethods(annotationClass, m -> {
                String name = m.getName();
                try {
                    Object result = m.invoke(annotation);
                    switch (name) {
                        case "using": {
                            Class using = processUsing((Class) result);
                            if (using != null) {
                                fieldInfo.readUsing = using;
                            }
                            break;
                        }
                        case "keyUsing": {
                            Class keyUsing = processUsing((Class) result);
                            if (keyUsing != null) {
                                fieldInfo.keyUsing = keyUsing;
                            }
                            break;
                        }
                        case "valueUsing": {
                            Class valueUsing = processUsing((Class) result);
                            if (valueUsing != null) {
                                fieldInfo.keyUsing = valueUsing;
                            }
                            break;
                        }
                        default:
                            break;
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private Class processUsing(Class using) {
            String usingName = using.getName();
            String noneClassName0 = "com.fasterxml.jackson.databind.JsonDeserializer$None";
            if (!noneClassName0.equals(usingName)
                    && ObjectReader.class.isAssignableFrom(using)
            ) {
                return using;
            }
            return null;
        }

        private void processJacksonJsonProperty(FieldInfo fieldInfo, Annotation annotation) {
            if (!JSONFactory.isUseJacksonAnnotation()) {
                return;
            }

            Class annotationClass = annotation.getClass();
            BeanUtils.annotationMethods(annotationClass, m -> {
                String name = m.getName();
                try {
                    Object result = m.invoke(annotation);
                    switch (name) {
                        case "value": {
                            String value = (String) result;
                            if (!value.isEmpty()
                                    && (fieldInfo.fieldName == null || fieldInfo.fieldName.isEmpty())
                            ) {
                                fieldInfo.fieldName = value;
                            }
                            break;
                        }
                        case "access": {
                            String access = ((Enum) result).name();
                            fieldInfo.ignore = "READ_ONLY".equals(access);
                            break;
                        }
                        case "required":
                            boolean required = (Boolean) result;
                            if (required) {
                                fieldInfo.required = true;
                            }
                            break;
                        default:
                            break;
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void processJacksonJsonSetter(FieldInfo fieldInfo, Annotation annotation) {
            Class annotationClass = annotation.getClass();
            BeanUtils.annotationMethods(annotationClass, m -> {
                String name = m.getName();
                try {
                    Object result = m.invoke(annotation);
                    switch (name) {
                        case "value": {
                            String value = (String) result;
                            if (!value.isEmpty()) {
                                fieldInfo.fieldName = value;
                            }
                            break;
                        }
                        default:
                            break;
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void processJacksonJsonAlias(FieldInfo fieldInfo, Annotation annotation) {
            Class annotationClass = annotation.getClass();
            BeanUtils.annotationMethods(annotationClass, m -> {
                String name = m.getName();
                try {
                    Object result = m.invoke(annotation);
                    if ("value".equals(name)) {
                        String[] values = (String[]) result;
                        if (values.length != 0) {
                            fieldInfo.alternateNames = values;
                        }
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void processJSONField1x(FieldInfo fieldInfo, Annotation annotation) {
            Class annotationClass = annotation.getClass();
            BeanUtils.annotationMethods(annotationClass, m -> {
                String name = m.getName();
                try {
                    Object result = m.invoke(annotation);
                    switch (name) {
                        case "name": {
                            String value = (String) result;
                            if (!value.isEmpty()) {
                                fieldInfo.fieldName = value;
                            }
                            break;
                        }
                        case "format": {
                            String format = (String) result;
                            if (!format.isEmpty()) {
                                format = format.trim();

                                if (format.indexOf('T') != -1 && !format.contains("'T'")) {
                                    format = format.replaceAll("T", "'T'");
                                }

                                fieldInfo.format = format;
                            }
                            break;
                        }
                        case "label": {
                            String label = (String) result;
                            if (!label.isEmpty()) {
                                fieldInfo.label = label;
                            }
                            break;
                        }
                        case "defaultValue": {
                            String value = (String) result;
                            if (!value.isEmpty()) {
                                fieldInfo.defaultValue = value;
                            }
                            break;
                        }
                        case "alternateNames": {
                            String[] alternateNames = (String[]) result;
                            if (alternateNames.length != 0) {
                                if (fieldInfo.alternateNames == null) {
                                    fieldInfo.alternateNames = alternateNames;
                                } else {
                                    Set nameSet = new LinkedHashSet<>();
                                    nameSet.addAll(Arrays.asList(alternateNames));
                                    nameSet.addAll(Arrays.asList(fieldInfo.alternateNames));
                                    fieldInfo.alternateNames = nameSet.toArray(new String[nameSet.size()]);
                                }
                            }
                            break;
                        }
                        case "ordinal": {
                            int ordinal = (Integer) result;
                            if (ordinal != 0) {
                                fieldInfo.ordinal = ordinal;
                            }
                            break;
                        }
                        case "deserialize": {
                            boolean serialize = (Boolean) result;
                            if (!serialize) {
                                fieldInfo.ignore = true;
                            }
                            break;
                        }
                        case "parseFeatures": {
                            Enum[] features = (Enum[]) result;
                            for (Enum feature : features) {
                                switch (feature.name()) {
                                    case "SupportAutoType":
                                        fieldInfo.features |= JSONReader.Feature.SupportAutoType.mask;
                                        break;
                                    case "SupportArrayToBean":
                                        fieldInfo.features |= JSONReader.Feature.SupportArrayToBean.mask;
                                        break;
                                    case "InitStringFieldAsEmpty":
                                        fieldInfo.features |= JSONReader.Feature.InitStringFieldAsEmpty.mask;
                                        break;
                                    default:
                                        break;
                                }
                            }
                            break;
                        }
                        case "deserializeUsing": {
                            Class deserializeUsing = (Class) result;
                            if (ObjectReader.class.isAssignableFrom(deserializeUsing)) {
                                fieldInfo.readUsing = deserializeUsing;
                            }
                            break;
                        }
                        case "unwrapped": {
                            boolean unwrapped = (Boolean) result;
                            if (unwrapped) {
                                fieldInfo.features |= FieldInfo.UNWRAPPED_MASK;
                            }
                            break;
                        }
                        default:
                            break;
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void getFieldInfo(FieldInfo fieldInfo, JSONField jsonField) {
            if (jsonField == null) {
                return;
            }

            String jsonFieldName = jsonField.name();
            if (!jsonFieldName.isEmpty()) {
                fieldInfo.fieldName = jsonFieldName;
            }

            String jsonFieldFormat = jsonField.format();
            if (!jsonFieldFormat.isEmpty()) {
                jsonFieldFormat = jsonFieldFormat.trim();
                if (jsonFieldFormat.indexOf('T') != -1 && !jsonFieldFormat.contains("'T'")) {
                    jsonFieldFormat = jsonFieldFormat.replaceAll("T", "'T'");
                }

                fieldInfo.format = jsonFieldFormat;
            }

            String label = jsonField.label();
            if (!label.isEmpty()) {
                label = label.trim();
                fieldInfo.label = label;
            }

            String defaultValue = jsonField.defaultValue();
            if (!defaultValue.isEmpty()) {
                fieldInfo.defaultValue = defaultValue;
            }

            String locale = jsonField.locale();
            if (!locale.isEmpty()) {
                String[] parts = locale.split("_");
                if (parts.length == 2) {
                    fieldInfo.locale = new Locale(parts[0], parts[1]);
                }
            }

            String[] alternateNames = jsonField.alternateNames();
            if (alternateNames.length != 0) {
                if (fieldInfo.alternateNames == null) {
                    fieldInfo.alternateNames = alternateNames;
                } else {
                    Set nameSet = new LinkedHashSet<>();
                    nameSet.addAll(Arrays.asList(alternateNames));
                    nameSet.addAll(Arrays.asList(fieldInfo.alternateNames));
                    fieldInfo.alternateNames = nameSet.toArray(new String[nameSet.size()]);
                }
            }

            boolean ignore = !jsonField.deserialize();
            if (!fieldInfo.ignore) {
                fieldInfo.ignore = ignore;
            }

            for (JSONReader.Feature feature : jsonField.deserializeFeatures()) {
                fieldInfo.features |= feature.mask;
                if (fieldInfo.ignore && !ignore && feature == JSONReader.Feature.FieldBased) {
                    fieldInfo.ignore = false;
                }
            }

            int ordinal = jsonField.ordinal();
            if (ordinal != 0) {
                fieldInfo.ordinal = ordinal;
            }

            boolean value = jsonField.value();
            if (value) {
                fieldInfo.features |= FieldInfo.VALUE_MASK;
            }

            if (jsonField.unwrapped()) {
                fieldInfo.features |= FieldInfo.UNWRAPPED_MASK;
            }

            if (jsonField.required()) {
                fieldInfo.required = true;
            }

            String schema = jsonField.schema().trim();
            if (!schema.isEmpty()) {
                fieldInfo.schema = schema;
            }

            Class deserializeUsing = jsonField.deserializeUsing();
            if (ObjectReader.class.isAssignableFrom(deserializeUsing)) {
                fieldInfo.readUsing = deserializeUsing;
            }

            String keyName = jsonField.arrayToMapKey().trim();
            if (!keyName.isEmpty()) {
                fieldInfo.arrayToMapKey = keyName;
            }
            Class arrayToMapDuplicateHandler = jsonField.arrayToMapDuplicateHandler();
            if (arrayToMapDuplicateHandler != Void.class) {
                fieldInfo.arrayToMapDuplicateHandler = arrayToMapDuplicateHandler;
            }
        }
    }

    private void getBeanInfo1xJSONPOJOBuilder(
            BeanInfo beanInfo,
            Class builderClass,
            Annotation builderAnnatation,
            Class builderAnnatationClass
    ) {
        BeanUtils.annotationMethods(builderAnnatationClass, method -> {
            try {
                String methodName = method.getName();
                switch (methodName) {
                    case "buildMethodName":
                    case "buildMethod": {
                        String buildMethodName = (String) method.invoke(builderAnnatation);
                        beanInfo.buildMethod = BeanUtils.buildMethod(builderClass, buildMethodName);
                        break;
                    }
                    case "withPrefix": {
                        String withPrefix = (String) method.invoke(builderAnnatation);
                        if (!withPrefix.isEmpty()) {
                            beanInfo.builderWithPrefix = withPrefix;
                        }
                        break;
                    }
                    default:
                        break;
                }
            } catch (Throwable ignored) {
            }
        });
    }

    private void getCreator(BeanInfo beanInfo, Class objectClass, Constructor constructor) {
        if (objectClass.isEnum()) {
            return;
        }

        Annotation[] annotations = getAnnotations(constructor);

        boolean creatorMethod = false;
        for (Annotation annotation : annotations) {
            Class annotationType = annotation.annotationType();

            JSONCreator jsonCreator = findAnnotation(annotation, JSONCreator.class);
            if (jsonCreator != null) {
                String[] createParameterNames = jsonCreator.parameterNames();
                if (createParameterNames.length != 0) {
                    beanInfo.createParameterNames = createParameterNames;
                }

                creatorMethod = true;
                if (jsonCreator == annotation) {
                    continue;
                }
            }

            switch (annotationType.getName()) {
                case "com.alibaba.fastjson.annotation.JSONCreator":
                case "com.alibaba.fastjson2.annotation.JSONCreator":
                    creatorMethod = true;
                    BeanUtils.annotationMethods(annotationType, m1 -> {
                        try {
                            if ("parameterNames".equals(m1.getName())) {
                                String[] createParameterNames = (String[]) m1.invoke(annotation);
                                if (createParameterNames.length != 0) {
                                    beanInfo.createParameterNames = createParameterNames;
                                }
                            }
                        } catch (Throwable ignored) {
                        }
                    });
                    break;
                case "com.fasterxml.jackson.annotation.JsonCreator":
                    if (JSONFactory.isUseJacksonAnnotation()) {
                        creatorMethod = true;
                    }
                    break;
                default:
                    break;
            }
        }

        if (!creatorMethod) {
            return;
        }

        Constructor targetConstructor = null;
        try {
            targetConstructor = objectClass.getDeclaredConstructor(constructor.getParameterTypes());
        } catch (NoSuchMethodException ignored) {
        }
        if (targetConstructor != null) {
            beanInfo.creatorConstructor = targetConstructor;
        }
    }

    private void getCreator(BeanInfo beanInfo, Class objectClass, Method method) {
        if (method.getDeclaringClass() == Enum.class) {
            return;
        }

        String methodName = method.getName();
        if (objectClass.isEnum()) {
            if ("values".equals(methodName)) {
                return;
            }
        }

        Annotation[] annotations = getAnnotations(method);

        boolean creatorMethod = false;
        JSONCreator jsonCreator = null;
        for (Annotation annotation : annotations) {
            Class annotationType = annotation.annotationType();
            jsonCreator = findAnnotation(annotation, JSONCreator.class);
            if (jsonCreator == annotation) {
                continue;
            }

            switch (annotationType.getName()) {
                case "com.alibaba.fastjson.annotation.JSONCreator":
                    creatorMethod = true;
                    BeanUtils.annotationMethods(annotationType, m1 -> {
                        try {
                            if ("parameterNames".equals(m1.getName())) {
                                String[] createParameterNames = (String[]) m1.invoke(annotation);
                                if (createParameterNames.length != 0) {
                                    beanInfo.createParameterNames = createParameterNames;
                                }
                            }
                        } catch (Throwable ignored) {
                        }
                    });
                    break;
                case "com.fasterxml.jackson.annotation.JsonCreator":
                    if (JSONFactory.isUseJacksonAnnotation()) {
                        creatorMethod = true;
                        BeanUtils.annotationMethods(annotationType, m1 -> {
                            try {
                                if ("parameterNames".equals(m1.getName())) {
                                    String[] createParameterNames = (String[]) m1.invoke(annotation);
                                    if (createParameterNames.length != 0) {
                                        beanInfo.createParameterNames = createParameterNames;
                                    }
                                }
                            } catch (Throwable ignored) {
                            }
                        });
                    }
                    break;
                default:
                    break;
            }
        }

        if (jsonCreator != null) {
            String[] createParameterNames = jsonCreator.parameterNames();
            if (createParameterNames.length != 0) {
                beanInfo.createParameterNames = createParameterNames;
            }

            creatorMethod = true;
        }

        if (!creatorMethod) {
            return;
        }

        Method targetMethod = null;
        try {
            targetMethod = objectClass.getDeclaredMethod(methodName, method.getParameterTypes());
        } catch (NoSuchMethodException ignored) {
        }

        if (targetMethod != null) {
            beanInfo.createMethod = targetMethod;
        }
    }

    @Override
    public ReaderAnnotationProcessor getAnnotationProcessor() {
        return annotationProcessor;
    }

    public void getBeanInfo(BeanInfo beanInfo, Class objectClass) {
        if (annotationProcessor != null) {
            annotationProcessor.getBeanInfo(beanInfo, objectClass);
        }
    }

    public void getFieldInfo(FieldInfo fieldInfo, Class objectClass, Field field) {
        if (annotationProcessor != null) {
            annotationProcessor.getFieldInfo(fieldInfo, objectClass, field);
        }
    }

    @Override
    public ObjectReader getObjectReader(ObjectReaderProvider provider, Type type) {
        if (type == String.class || type == CharSequence.class) {
            return ObjectReaderImplString.INSTANCE;
        }

        if (type == char.class || type == Character.class) {
            return ObjectReaderImplCharacter.INSTANCE;
        }

        if (type == boolean.class || type == Boolean.class) {
            return ObjectReaderImplBoolean.INSTANCE;
        }

        if (type == byte.class || type == Byte.class) {
            return ObjectReaderImplByte.INSTANCE;
        }

        if (type == short.class || type == Short.class) {
            return ObjectReaderImplShort.INSTANCE;
        }

        if (type == int.class || type == Integer.class) {
            return ObjectReaderImplInteger.INSTANCE;
        }

        if (type == long.class || type == Long.class) {
            return ObjectReaderImplInt64.INSTANCE;
        }

        if (type == float.class || type == Float.class) {
            return ObjectReaderImplFloat.INSTANCE;
        }

        if (type == double.class || type == Double.class) {
            return ObjectReaderImplDouble.INSTANCE;
        }

        if (type == BigInteger.class) {
            return ObjectReaderImplBigInteger.INSTANCE;
        }

        if (type == BigDecimal.class) {
            return ObjectReaderImplBigDecimal.INSTANCE;
        }

        if (type == Number.class) {
            return ObjectReaderImplNumber.INSTANCE;
        }

        if (type == BitSet.class) {
            return ObjectReaderImplBitSet.INSTANCE;
        }

        if (type == OptionalInt.class) {
            return ObjectReaderImplOptionalInt.INSTANCE;
        }

        if (type == OptionalLong.class) {
            return ObjectReaderImplOptionalLong.INSTANCE;
        }

        if (type == OptionalDouble.class) {
            return ObjectReaderImplOptionalDouble.INSTANCE;
        }

        if (type == Optional.class) {
            return ObjectReaderImplOptional.INSTANCE;
        }

        if (type == UUID.class) {
            return ObjectReaderImplUUID.INSTANCE;
        }

        if (type == Duration.class) {
            return new ObjectReaderImplFromString(Duration.class, (Function) Duration::parse);
        }

        if (type == Period.class) {
            return new ObjectReaderImplFromString(Period.class, (Function) Period::parse);
        }

        if (type == AtomicBoolean.class) {
            return new ObjectReaderImplFromBoolean(
                    AtomicBoolean.class,
                    (Function) AtomicBoolean::new
            );
        }

        if (type == URI.class) {
            return new ObjectReaderImplFromString<>(
                    URI.class,
                    URI::create
            );
        }

        if (type == Charset.class) {
            return new ObjectReaderImplFromString<>(Charset.class, Charset::forName);
        }

        if (type == File.class) {
            return new ObjectReaderImplFromString<>(File.class, File::new);
        }

        if (type == Path.class) {
            return new ObjectReaderImplFromString<>(
                    Path.class,
                    Paths::get
            );
        }

        if (type == URL.class) {
            return new ObjectReaderImplFromString<>(
                    URL.class,
                    e -> {
                        try {
                            return new URL(e);
                        } catch (MalformedURLException ex) {
                            throw new JSONException("read URL error", ex);
                        }
                    });
        }

        if (type == Pattern.class) {
            return new ObjectReaderImplFromString<>(Pattern.class, Pattern::compile);
        }

        if (type == Class.class) {
            return ObjectReaderImplClass.INSTANCE;
        }

        if (type == Method.class) {
            return new ObjectReaderImplMethod();
        }

        if (type == Field.class) {
            return new ObjectReaderImplField();
        }

        if (type == Type.class) {
            return ObjectReaderImplClass.INSTANCE;
        }

        String internalMixin = null;
        String typeName = type.getTypeName();
        switch (typeName) {
            case "com.google.common.collect.AbstractMapBasedMultimap$WrappedSet":
                return null;
            case "org.springframework.util.LinkedMultiValueMap":
                return ObjectReaderImplMap.of(type, (Class) type, 0L);
            case "org.springframework.security.core.authority.RememberMeAuthenticationToken":
                internalMixin = "org.springframework.security.jackson2.AnonymousAuthenticationTokenMixin";
                break;
            case "org.springframework.security.core.authority.AnonymousAuthenticationToken":
                internalMixin = "org.springframework.security.jackson2.RememberMeAuthenticationTokenMixin";
                break;
            case "org.springframework.security.core.authority.SimpleGrantedAuthority":
                internalMixin = "org.springframework.security.jackson2.SimpleGrantedAuthorityMixin";
                break;
            case "org.springframework.security.core.userdetails.User":
                internalMixin = "org.springframework.security.jackson2.UserMixin";
                break;
            case "org.springframework.security.authentication.UsernamePasswordAuthenticationToken":
                internalMixin = "org.springframework.security.jackson2.UsernamePasswordAuthenticationTokenMixin";
                break;
            case "org.springframework.security.authentication.BadCredentialsException":
                internalMixin = "org.springframework.security.jackson2.BadCredentialsExceptionMixin";
                break;
            case "org.springframework.security.web.csrf.DefaultCsrfToken":
                internalMixin = "org.springframework.security.web.jackson2.DefaultCsrfTokenMixin";
                break;
            case "org.springframework.security.web.savedrequest.SavedCookie":
                internalMixin = "org.springframework.security.web.jackson2.SavedCookieMixin";
                break;
            case "org.springframework.security.web.authentication.WebAuthenticationDetails":
                internalMixin = "org.springframework.security.web.jackson2.WebAuthenticationDetailsMixin";
                break;
        }

        if (internalMixin != null) {
            Class mixin = provider.mixInCache.get(type);
            if (mixin == null) {
                mixin = TypeUtils.loadClass(internalMixin);
                if (mixin == null) {
                    if ("org.springframework.security.jackson2.SimpleGrantedAuthorityMixin".equals(internalMixin)) {
                        mixin = TypeUtils.loadClass("com.alibaba.fastjson2.internal.mixin.spring.SimpleGrantedAuthorityMixin");
                    }
                }

                if (mixin != null) {
                    provider.mixInCache.putIfAbsent((Class) type, mixin);
                }
            }
        }

        if (type == Map.class || type == AbstractMap.class) {
            return ObjectReaderImplMap.of(null, (Class) type, 0);
        }

        if (type == ConcurrentMap.class || type == ConcurrentHashMap.class) {
            return typedMap((Class) type, ConcurrentHashMap.class, null, Object.class);
        }

        if (type == ConcurrentNavigableMap.class
                || type == ConcurrentSkipListMap.class
        ) {
            return typedMap((Class) type, ConcurrentSkipListMap.class, null, Object.class);
        }

        if (type == SortedMap.class
                || type == NavigableMap.class
                || type == TreeMap.class
        ) {
            return typedMap((Class) type, TreeMap.class, null, Object.class);
        }

        if (type == Calendar.class || "javax.xml.datatype.XMLGregorianCalendar".equals(typeName)) {
            return ObjectReaderImplCalendar.INSTANCE;
        }

        if (type == Date.class) {
            return ObjectReaderImplDate.INSTANCE;
        }

        if (type == LocalDate.class) {
            return ObjectReaderImplLocalDate.INSTANCE;
        }

        if (type == LocalTime.class) {
            return ObjectReaderImplLocalTime.INSTANCE;
        }

        if (type == LocalDateTime.class) {
            return ObjectReaderImplLocalDateTime.INSTANCE;
        }

        if (type == ZonedDateTime.class) {
            return ObjectReaderImplZonedDateTime.INSTANCE;
        }

        if (type == OffsetDateTime.class) {
            return ObjectReaderImplOffsetDateTime.INSTANCE;
        }

        if (type == OffsetTime.class) {
            return ObjectReaderImplOffsetTime.INSTANCE;
        }

        if (type == ZoneOffset.class) {
            return new ObjectReaderImplFromString<>(ZoneOffset.class, ZoneOffset::of);
        }

        if (type == Instant.class) {
            return ObjectReaderImplInstant.INSTANCE;
        }

        if (type == Locale.class) {
            return ObjectReaderImplLocale.INSTANCE;
        }

        if (type == Currency.class) {
            return ObjectReaderImplCurrency.INSTANCE;
        }

        if (type == ZoneId.class) {
//            return ZoneIdImpl.INSTANCE;
            // ZoneId.of(strVal)
            return new ObjectReaderImplFromString<>(ZoneId.class, ZoneId::of);
        }

        if (type == TimeZone.class) {
            return new ObjectReaderImplFromString<>(TimeZone.class, TimeZone::getTimeZone);
        }

        if (type == char[].class) {
            return ObjectReaderImplCharValueArray.INSTANCE;
        }

        if (type == float[].class) {
            return ObjectReaderImplFloatValueArray.INSTANCE;
        }

        if (type == double[].class) {
            return ObjectReaderImplDoubleValueArray.INSTANCE;
        }

        if (type == boolean[].class) {
            return ObjectReaderImplBoolValueArray.INSTANCE;
        }

        if (type == byte[].class) {
            return ObjectReaderImplInt8ValueArray.INSTANCE;
        }

        if (type == short[].class) {
            return ObjectReaderImplInt16ValueArray.INSTANCE;
        }

        if (type == int[].class) {
            return ObjectReaderImplInt32ValueArray.INSTANCE;
        }

        if (type == long[].class) {
            return ObjectReaderImplInt64ValueArray.INSTANCE;
        }

        if (type == Byte[].class) {
            return ObjectReaderImplInt8Array.INSTANCE;
        }

        if (type == Short[].class) {
            return ObjectReaderImplInt16Array.INSTANCE;
        }

        if (type == Integer[].class) {
            return ObjectReaderImplInt32Array.INSTANCE;
        }

        if (type == Long[].class) {
            return ObjectReaderImplInt64Array.INSTANCE;
        }

        if (type == Float[].class) {
            return ObjectReaderImplFloatArray.INSTANCE;
        }

        if (type == Double[].class) {
            return ObjectReaderImplDoubleArray.INSTANCE;
        }

        if (type == Number[].class) {
            return ObjectReaderImplNumberArray.INSTANCE;
        }

        if (type == String[].class) {
            return ObjectReaderImplStringArray.INSTANCE;
        }

        if (type == AtomicInteger.class) {
            return new ObjectReaderImplFromInt(AtomicInteger.class, AtomicInteger::new);
        }

        if (type == AtomicLong.class) {
            return new ObjectReaderImplFromLong(AtomicLong.class, AtomicLong::new);
        }

        if (type == AtomicIntegerArray.class) {
            return new ObjectReaderImplInt32ValueArray(AtomicIntegerArray.class, AtomicIntegerArray::new);
            //return ObjectReaderImplAtomicIntegerArray.INSTANCE;
        }

        if (type == AtomicLongArray.class) {
            return new ObjectReaderImplInt64ValueArray(AtomicLongArray.class, AtomicLongArray::new);
//            return ObjectReaderImplAtomicLongArray.INSTANCE;
        }

        if (type == AtomicReference.class) {
            return ObjectReaderImplAtomicReference.INSTANCE;
        }

        if (type instanceof MultiType) {
            return new ObjectArrayReaderMultiType((MultiType) type);
        }

        if (type instanceof MapMultiValueType) {
            return new ObjectReaderImplMapMultiValueType((MapMultiValueType) type);
        }

        if (type == StringBuffer.class || type == StringBuilder.class) {
            try {
                Class objectClass = (Class) type;
                return new ObjectReaderImplValue(
                        objectClass,
                        String.class,
                        String.class,
                        0,
                        null,
                        null,
                        null,
                        objectClass.getConstructor(String.class),
                        null,
                        null
                );
            } catch (NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        }

        if (type == Iterable.class
                || type == Collection.class
                || type == List.class
                || type == AbstractCollection.class
                || type == AbstractList.class
                || type == ArrayList.class
        ) {
            return ObjectReaderImplList.of(type, null, 0);
            // return new ObjectReaderImplList(type, (Class) type, ArrayList.class, Object.class, null);
        }

        if (type == Queue.class
                || type == Deque.class
                || type == AbstractSequentialList.class
                || type == LinkedList.class) {
//            return new ObjectReaderImplList(type, (Class) type, LinkedList.class, Object.class, null);
            return ObjectReaderImplList.of(type, null, 0);
        }

        if (type == Set.class || type == AbstractSet.class || type == EnumSet.class) {
//            return new ObjectReaderImplList(type, (Class) type, HashSet.class, Object.class, null);
            return ObjectReaderImplList.of(type, null, 0);
        }

        if (type == NavigableSet.class || type == SortedSet.class) {
//            return new ObjectReaderImplList(type, (Class) type, TreeSet.class, Object.class, null);
            return ObjectReaderImplList.of(type, null, 0);
        }

        if (type == ConcurrentLinkedDeque.class
                || type == ConcurrentLinkedQueue.class
                || type == ConcurrentSkipListSet.class
                || type == LinkedHashSet.class
                || type == HashSet.class
                || type == TreeSet.class
                || type == CopyOnWriteArrayList.class
        ) {
//            return new ObjectReaderImplList(type, (Class) type, (Class) type, Object.class, null);
            return ObjectReaderImplList.of(type, null, 0);
        }

        if (type == ObjectReaderImplList.CLASS_EMPTY_SET
                || type == ObjectReaderImplList.CLASS_EMPTY_LIST
                || type == ObjectReaderImplList.CLASS_SINGLETON
                || type == ObjectReaderImplList.CLASS_SINGLETON_LIST
                || type == ObjectReaderImplList.CLASS_ARRAYS_LIST
                || type == ObjectReaderImplList.CLASS_UNMODIFIABLE_COLLECTION
                || type == ObjectReaderImplList.CLASS_UNMODIFIABLE_LIST
                || type == ObjectReaderImplList.CLASS_UNMODIFIABLE_SET
                || type == ObjectReaderImplList.CLASS_UNMODIFIABLE_SORTED_SET
                || type == ObjectReaderImplList.CLASS_UNMODIFIABLE_NAVIGABLE_SET
        ) {
//            return new ObjectReaderImplList(type, (Class) type, (Class) type, Object.class, null);
            return ObjectReaderImplList.of(type, null, 0);
        }

        if (type == TypeUtils.CLASS_SINGLE_SET) {
//            return SingletonSetImpl.INSTANCE;
            return ObjectReaderImplList.of(type, null, 0);
        }

        if (type == Object.class
                || type == Cloneable.class
                || type == Closeable.class
                || type == Serializable.class
                || type == Comparable.class
        ) {
            return ObjectReaderImplObject.INSTANCE;
        }

        if (type == Map.Entry.class) {
            return new ObjectReaderImplMapEntry(null, null);
        }

        if (type instanceof Class) {
            Class objectClass = (Class) type;

            if (isExtendedMap(objectClass)) {
                return null;
            }

            if (Map.class.isAssignableFrom(objectClass)) {
                return ObjectReaderImplMap.of(null, objectClass, 0);
            }

            if (Collection.class.isAssignableFrom(objectClass)) {
                return ObjectReaderImplList.of(objectClass, objectClass, 0);
            }

            if (objectClass.isArray()) {
                Class componentType = objectClass.getComponentType();
                if (componentType == Object.class) {
                    return ObjectArrayReader.INSTANCE;
                }
                return new ObjectArrayTypedReader(objectClass);
            }

            if (JSONPObject.class.isAssignableFrom(objectClass)) {
                return new ObjectReaderImplJSONP(objectClass);
            }

            ObjectReaderCreator creator = JSONFactory
                    .getDefaultObjectReaderProvider()
                    .getCreator();

            if (objectClass == StackTraceElement.class) {
                try {
                    Constructor constructor = objectClass.getConstructor(
                            String.class,
                            String.class,
                            String.class,
                            int.class);

                    return creator
                            .createObjectReaderNoneDefaultConstructor(
                                    constructor,
                                    "className",
                                    "methodName",
                                    "fileName",
                                    "lineNumber");
                } catch (Throwable ignored) {
                    //
                }
            }
        }

        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Type rawType = parameterizedType.getRawType();

            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

            if (actualTypeArguments.length == 2) {
                Type actualTypeParam0 = actualTypeArguments[0];
                Type actualTypeParam1 = actualTypeArguments[1];

                if (rawType == Map.class
                        || rawType == AbstractMap.class
                        || rawType == HashMap.class
                ) {
                    return typedMap((Class) rawType, HashMap.class, actualTypeParam0, actualTypeParam1);
                }

                if (rawType == ConcurrentMap.class
                        || rawType == ConcurrentHashMap.class
                ) {
                    return typedMap((Class) rawType, ConcurrentHashMap.class, actualTypeParam0, actualTypeParam1);
                }

                if (rawType == ConcurrentNavigableMap.class
                        || rawType == ConcurrentSkipListMap.class
                ) {
                    return typedMap((Class) rawType, ConcurrentSkipListMap.class, actualTypeParam0, actualTypeParam1);
                }

                if (rawType == LinkedHashMap.class
                        || rawType == TreeMap.class
                        || rawType == Hashtable.class) {
                    return typedMap((Class) rawType, (Class) rawType, actualTypeParam0, actualTypeParam1);
                }

                if (rawType == Map.Entry.class) {
                    return new ObjectReaderImplMapEntry(actualTypeParam0, actualTypeParam1);
                }

                switch (rawType.getTypeName()) {
                    case "com.google.common.collect.ImmutableMap":
                    case "com.google.common.collect.RegularImmutableMap":
                        return new ObjectReaderImplMapTyped((Class) rawType, HashMap.class, actualTypeParam0, actualTypeParam1, 0, GuavaSupport.immutableMapConverter());
                    case "com.google.common.collect.SingletonImmutableBiMap":
                        return new ObjectReaderImplMapTyped((Class) rawType, HashMap.class, actualTypeParam0, actualTypeParam1, 0, GuavaSupport.singletonBiMapConverter());
                    case "org.springframework.util.LinkedMultiValueMap":
                        return ObjectReaderImplMap.of(type, (Class) rawType, 0L);
                    case "org.apache.commons.lang3.tuple.Pair":
                    case "org.apache.commons.lang3.tuple.ImmutablePair":
                        return new ApacheLang3Support.PairReader((Class) rawType, actualTypeParam0, actualTypeParam1);
                }
            } else if (actualTypeArguments.length == 1) {
                Type itemType = actualTypeArguments[0];
                Class itemClass = TypeUtils.getMapping(itemType);

                if (rawType == Iterable.class
                        || rawType == Collection.class
                        || rawType == List.class
                        || rawType == AbstractCollection.class
                        || rawType == AbstractList.class
                        || rawType == ArrayList.class) {
                    if (itemClass == String.class) {
                        return new ObjectReaderImplListStr((Class) rawType, ArrayList.class);
                    } else if (itemClass == Long.class) {
                        return new ObjectReaderImplListInt64((Class) rawType, ArrayList.class);
                    } else {
                        return ObjectReaderImplList.of(type, null, 0);
                    }
                }

                if (rawType == Queue.class
                        || rawType == Deque.class
                        || rawType == AbstractSequentialList.class
                        || rawType == LinkedList.class) {
                    if (itemClass == String.class) {
                        return new ObjectReaderImplListStr((Class) rawType, LinkedList.class);
                    } else if (itemClass == Long.class) {
                        return new ObjectReaderImplListInt64((Class) rawType, LinkedList.class);
                    } else {
                        return ObjectReaderImplList.of(type, null, 0);
                    }
                }

                if (rawType == Set.class || rawType == AbstractSet.class || rawType == EnumSet.class) {
                    if (itemClass == String.class) {
                        return new ObjectReaderImplListStr((Class) rawType, HashSet.class);
                    } else if (itemClass == Long.class) {
                        return new ObjectReaderImplListInt64((Class) rawType, HashSet.class);
                    } else {
                        return ObjectReaderImplList.of(type, null, 0);
                    }
                }

                if (rawType == NavigableSet.class || rawType == SortedSet.class) {
                    if (itemType == String.class) {
                        return new ObjectReaderImplListStr((Class) rawType, TreeSet.class);
                    } else if (itemClass == Long.class) {
                        return new ObjectReaderImplListInt64((Class) rawType, TreeSet.class);
                    } else {
                        return ObjectReaderImplList.of(type, null, 0);
                    }
                }

                if (rawType == ConcurrentLinkedDeque.class
                        || rawType == ConcurrentLinkedQueue.class
                        || rawType == ConcurrentSkipListSet.class
                        || rawType == LinkedHashSet.class
                        || rawType == HashSet.class
                        || rawType == TreeSet.class
                        || rawType == CopyOnWriteArrayList.class
                ) {
                    if (itemType == String.class) {
                        return new ObjectReaderImplListStr((Class) rawType, (Class) rawType);
                    } else if (itemClass == Long.class) {
                        return new ObjectReaderImplListInt64((Class) rawType, (Class) rawType);
                    } else {
                        return ObjectReaderImplList.of(type, null, 0);
                    }
                }

                switch (rawType.getTypeName()) {
                    case "com.google.common.collect.ImmutableList":
                    case "com.google.common.collect.ImmutableSet":
                    case "com.google.common.collect.SingletonImmutableSet":
                        return ObjectReaderImplList.of(type, null, 0);
                }

                if (rawType == Optional.class) {
                    return ObjectReaderImplOptional.of(type, null, null);
                }

                if (rawType == AtomicReference.class) {
                    return new ObjectReaderImplAtomicReference(itemType);
                }

                if (itemType instanceof WildcardType) {
                    return getObjectReader(provider, rawType);
                }
            }

            return null;
        }

        if (type instanceof GenericArrayType) {
            return new ObjectReaderImplGenericArray((GenericArrayType) type);
        }

        if (type instanceof WildcardType) {
            Type[] upperBounds = ((WildcardType) type).getUpperBounds();
            if (upperBounds.length == 1) {
                return getObjectReader(provider, upperBounds[0]);
            }
        }

        if (type == ParameterizedType.class) {
            return ObjectReaders.ofReflect(ParameterizedTypeImpl.class);
        }

        switch (typeName) {
            case "java.sql.Time":
                return JdbcSupport.createTimeReader((Class) type, null, null);
            case "java.sql.Timestamp":
                return JdbcSupport.createTimestampReader((Class) type, null, null);
            case "java.sql.Date":
                return JdbcSupport.createDateReader((Class) type, null, null);
            case "java.util.RegularEnumSet":
            case "java.util.JumboEnumSet":
                return ObjectReaderImplList.of(type, TypeUtils.getClass(type), 0);
            case "org.joda.time.Chronology":
                return JodaSupport.createChronologyReader((Class) type);
            case "org.joda.time.LocalDate":
                return JodaSupport.createLocalDateReader((Class) type);
            case "org.joda.time.LocalDateTime":
                return JodaSupport.createLocalDateTimeReader((Class) type);
            case "org.joda.time.Instant":
                return JodaSupport.createInstantReader((Class) type);
            case "org.joda.time.DateTime":
                return new ObjectReaderImplZonedDateTime(new JodaSupport.DateTimeFromZDT());
            case "javax.money.CurrencyUnit":
                return MoneySupport.createCurrencyUnitReader();
            case "javax.money.MonetaryAmount":
            case "javax.money.Money":
                return MoneySupport.createMonetaryAmountReader();
            case "javax.money.NumberValue":
                return MoneySupport.createNumberValueReader();
            case "java.net.InetSocketAddress":
                return new ObjectReaderMisc((Class) type);
            case "java.net.InetAddress":
                return ObjectReaderImplValue.of((Class) type, String.class, address -> {
                    try {
                        return InetAddress.getByName(address);
                    } catch (UnknownHostException e) {
                        throw new JSONException("create address error", e);
                    }
                });
            case "java.text.SimpleDateFormat":
                return ObjectReaderImplValue.of((Class) type, String.class, SimpleDateFormat::new);
            case "java.lang.Throwable":
            case "java.lang.Exception":
            case "java.lang.IllegalStateException":
            case "java.lang.RuntimeException":
            case "java.io.IOException":
            case "java.io.UncheckedIOException":
                return new ObjectReaderException((Class) type);
            case "java.nio.HeapByteBuffer":
            case "java.nio.ByteBuffer":
                return new ObjectReaderImplInt8ValueArray(ByteBuffer::wrap, null);
            case "org.apache.commons.lang3.tuple.Pair":
            case "org.apache.commons.lang3.tuple.ImmutablePair":
                return new ApacheLang3Support.PairReader((Class) type, Object.class, Object.class);
            case "com.google.common.collect.ImmutableList":
            case "com.google.common.collect.ImmutableSet":
            case "com.google.common.collect.SingletonImmutableSet":
            case "com.google.common.collect.RegularImmutableSet":
            case "com.google.common.collect.AbstractMapBasedMultimap$RandomAccessWrappedList":
                return ObjectReaderImplList.of(type, null, 0);
            case "com.carrotsearch.hppc.ByteArrayList":
            case "com.carrotsearch.hppc.ShortArrayList":
            case "com.carrotsearch.hppc.IntArrayList":
            case "com.carrotsearch.hppc.IntHashSet":
            case "com.carrotsearch.hppc.LongArrayList":
            case "com.carrotsearch.hppc.LongHashSet":
            case "com.carrotsearch.hppc.CharArrayList":
            case "com.carrotsearch.hppc.CharHashSet":
            case "com.carrotsearch.hppc.FloatArrayList":
            case "com.carrotsearch.hppc.DoubleArrayList":
            case "gnu.trove.list.array.TByteArrayList":
            case "gnu.trove.list.array.TCharArrayList":
            case "gnu.trove.list.array.TShortArrayList":
            case "gnu.trove.list.array.TIntArrayList":
            case "gnu.trove.list.array.TLongArrayList":
            case "gnu.trove.list.array.TFloatArrayList":
            case "gnu.trove.list.array.TDoubleArrayList":
            case "gnu.trove.set.hash.TByteHashSet":
            case "gnu.trove.set.hash.TShortHashSet":
            case "gnu.trove.set.hash.TIntHashSet":
            case "gnu.trove.set.hash.TLongHashSet":
            case "org.bson.types.Decimal128":
                return LambdaMiscCodec.getObjectReader((Class) type);
            case "java.awt.Color":
                try {
                    Constructor constructor = ((Class) type).getConstructor(int.class, int.class, int.class, int.class);
                    return ObjectReaderCreator.INSTANCE.createObjectReaderNoneDefaultConstructor(constructor, "r", "g", "b", "alpha");
                } catch (Throwable ignored) {
                    // ignored
                }
            default:
                break;
        }

        return null;
    }

    public static ObjectReader typedMap(Class mapType, Class instanceType, Type keyType, Type valueType) {
        if ((keyType == null || keyType == String.class) && valueType == String.class) {
            return new ObjectReaderImplMapString(mapType, instanceType, 0);
        }
        return new ObjectReaderImplMapTyped(mapType, instanceType, keyType, valueType, 0, null);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy