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

shade.com.alibaba.fastjson2.writer.ObjectWriterBaseModule Maven / Gradle / Ivy

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

import com.alibaba.fastjson2.JSONFactory;
import com.alibaba.fastjson2.JSONPObject;
import com.alibaba.fastjson2.JSONPath;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.annotation.*;
import com.alibaba.fastjson2.codec.BeanInfo;
import com.alibaba.fastjson2.codec.FieldInfo;
import com.alibaba.fastjson2.filter.Filter;
import com.alibaba.fastjson2.modules.ObjectWriterAnnotationProcessor;
import com.alibaba.fastjson2.modules.ObjectWriterModule;
import com.alibaba.fastjson2.support.LambdaMiscCodec;
import com.alibaba.fastjson2.support.money.MoneySupport;
import com.alibaba.fastjson2.util.*;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.time.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.*;

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

public class ObjectWriterBaseModule
        implements ObjectWriterModule {
    static ObjectWriterAdapter STACK_TRACE_ELEMENT_WRITER;

    final ObjectWriterProvider provider;
    final WriterAnnotationProcessor annotationProcessor;

    public ObjectWriterBaseModule(ObjectWriterProvider provider) {
        this.provider = provider;
        this.annotationProcessor = new WriterAnnotationProcessor();
    }

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

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

    public class WriterAnnotationProcessor
            implements ObjectWriterAnnotationProcessor {
        @Override
        public void getBeanInfo(BeanInfo beanInfo, Class objectClass) {
            if (objectClass != null) {
                Class superclass = objectClass.getSuperclass();
                if (superclass != Object.class && superclass != null && superclass != Enum.class) {
                    getBeanInfo(beanInfo, superclass);

                    if (beanInfo.seeAlso != null && beanInfo.seeAlsoNames != null) {
                        for (int i = 0; i < beanInfo.seeAlso.length; i++) {
                            Class seeAlso = beanInfo.seeAlso[i];
                            if (seeAlso == objectClass && i < beanInfo.seeAlsoNames.length) {
                                String seeAlsoName = beanInfo.seeAlsoNames[i];
                                if (seeAlsoName != null && seeAlsoName.length() != 0) {
                                    beanInfo.typeName = seeAlsoName;
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            Annotation jsonType1x = null;
            JSONType jsonType = null;
            Annotation[] annotations = getAnnotations(objectClass);
            for (int i = 0; i < annotations.length; i++) {
                Annotation annotation = annotations[i];
                Class annotationType = annotation.annotationType();
                if (jsonType == null) {
                    jsonType = findAnnotation(annotation, JSONType.class);
                }
                if (jsonType == annotation) {
                    continue;
                }

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

                boolean useJacksonAnnotation = JSONFactory.isUseJacksonAnnotation();
                switch (annotationType.getName()) {
                    case "com.alibaba.fastjson.annotation.JSONType":
                        jsonType1x = annotation;
                        break;
                    case "com.fasterxml.jackson.annotation.JsonIgnoreProperties":
                        if (useJacksonAnnotation) {
                            processJacksonJsonIgnoreProperties(beanInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonPropertyOrder":
                        if (useJacksonAnnotation) {
                            processJacksonJsonPropertyOrder(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.JsonTypeInfo":
                        if (useJacksonAnnotation) {
                            processJacksonJsonTypeInfo(beanInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.databind.annotation.JsonSerialize":
                        if (useJacksonAnnotation) {
                            processJacksonJsonSerialize(beanInfo, annotation);
                            if (beanInfo.serializer != null && Enum.class.isAssignableFrom(objectClass)) {
                                beanInfo.writeEnumAsJavaBean = true;
                            }
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonTypeName":
                        if (useJacksonAnnotation) {
                            processJacksonJsonTypeName(beanInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonSubTypes":
                        if (useJacksonAnnotation) {
                            processJacksonJsonSubTypes(beanInfo, annotation);
                        }
                        break;
                    case "kotlin.Metadata":
                        beanInfo.kotlin = true;
                        KotlinUtils.getConstructor(objectClass, beanInfo);
                        break;
                    default:
                        break;
                }
            }

            if (jsonType == null) {
                Class mixInSource = provider.mixInCache.get(objectClass);

                if (mixInSource != null) {
                    beanInfo.mixIn = true;

                    Annotation[] mixInAnnotations = getAnnotations(mixInSource);
                    for (int i = 0; i < mixInAnnotations.length; i++) {
                        Annotation annotation = mixInAnnotations[i];
                        Class annotationType = annotation.annotationType();
                        jsonType = findAnnotation(annotation, JSONType.class);
                        if (jsonType == annotation) {
                            continue;
                        }

                        String annotationTypeName = annotationType.getName();
                        if ("com.alibaba.fastjson.annotation.JSONType".equals(annotationTypeName)) {
                            jsonType1x = annotation;
                        }
                    }
                }
            }

            if (jsonType != null) {
                Class[] classes = jsonType.seeAlso();
                if (classes.length != 0) {
                    beanInfo.seeAlso = classes;
                }

                String typeKey = jsonType.typeKey();
                if (!typeKey.isEmpty()) {
                    beanInfo.typeKey = typeKey;
                }

                String typeName = jsonType.typeName();
                if (!typeName.isEmpty()) {
                    beanInfo.typeName = typeName;
                }

                for (JSONWriter.Feature feature : jsonType.serializeFeatures()) {
                    beanInfo.writerFeatures |= feature.mask;
                }

                beanInfo.namingStrategy =
                        jsonType.naming().name();

                String[] ignores = jsonType.ignores();
                if (ignores.length > 0) {
                    beanInfo.ignores = ignores;
                }

                String[] includes = jsonType.includes();
                if (includes.length > 0) {
                    beanInfo.includes = includes;
                }

                String[] orders = jsonType.orders();
                if (orders.length > 0) {
                    beanInfo.orders = orders;
                }

                Class serializer = jsonType.serializer();
                if (ObjectWriter.class.isAssignableFrom(serializer)) {
                    beanInfo.serializer = serializer;
                }

                Class[] serializeFilters = jsonType.serializeFilters();
                if (serializeFilters.length != 0) {
                    beanInfo.serializeFilters = serializeFilters;
                }

                String format = jsonType.format();
                if (!format.isEmpty()) {
                    beanInfo.format = format;
                }

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

                if (!jsonType.alphabetic()) {
                    beanInfo.alphabetic = false;
                }

                if (jsonType.writeEnumAsJavaBean()) {
                    beanInfo.writeEnumAsJavaBean = true;
                }
            } else if (jsonType1x != null) {
                final Annotation annotation = jsonType1x;
                BeanUtils.annotationMethods(jsonType1x.annotationType(), method -> BeanUtils.processJSONType1x(beanInfo, annotation, method));
            }

            if (beanInfo.seeAlso != null && beanInfo.seeAlso.length != 0
                    && (beanInfo.typeName == null || beanInfo.typeName.length() == 0)) {
                for (Class seeAlsoClass : beanInfo.seeAlso) {
                    if (seeAlsoClass == objectClass) {
                        beanInfo.typeName = objectClass.getSimpleName();
                        break;
                    }
                }
            }
        }

        @Override
        public void getFieldInfo(BeanInfo beanInfo, 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(beanInfo, fieldInfo, mixInSource, mixInField);
                    }
                }
            }

            Class fieldClassMixInSource = provider.mixInCache.get(field.getType());
            if (fieldClassMixInSource != null) {
                fieldInfo.fieldClassMixIn = true;
            }

            int modifiers = field.getModifiers();
            boolean isTransient = Modifier.isTransient(modifiers);
            if (isTransient) {
                fieldInfo.ignore = true;
            }

            JSONField jsonField = null;
            Annotation[] annotations = getAnnotations(field);
            for (Annotation annotation : annotations) {
                Class annotationType = annotation.annotationType();
                if (jsonField == null) {
                    jsonField = findAnnotation(annotation, JSONField.class);
                    if (jsonField == annotation) {
                        continue;
                    }
                }

                String annotationTypeName = annotationType.getName();
                boolean useJacksonAnnotation = JSONFactory.isUseJacksonAnnotation();
                switch (annotationTypeName) {
                    case "com.fasterxml.jackson.annotation.JsonIgnore":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonIgnore":
                        if (useJacksonAnnotation) {
                            processJacksonJsonIgnore(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonAnyGetter":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonAnyGetter":
                        if (useJacksonAnnotation) {
                            fieldInfo.features |= FieldInfo.UNWRAPPED_MASK;
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonValue":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonValue":
                        if (useJacksonAnnotation) {
                            fieldInfo.features |= FieldInfo.VALUE_MASK;
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonRawValue":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonRawValue":
                        if (useJacksonAnnotation) {
                            fieldInfo.features |= FieldInfo.RAW_VALUE_MASK;
                        }
                        break;
                    case "com.alibaba.fastjson.annotation.JSONField":
                        processJSONField1x(fieldInfo, annotation);
                        break;
                    case "com.fasterxml.jackson.annotation.JsonProperty":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonProperty":
                        if (useJacksonAnnotation) {
                            processJacksonJsonProperty(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonFormat":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonFormat":
                        if (useJacksonAnnotation) {
                            processJacksonJsonFormat(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonInclude":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonInclude":
                        if (useJacksonAnnotation) {
                            processJacksonJsonInclude(beanInfo, annotation);
                        }
                        break;
                    case "com.alibaba.fastjson2.adapter.jackson.databind.annotation.JsonSerialize":
                    case "com.fasterxml.jackson.databind.annotation.JsonSerialize":
                        if (useJacksonAnnotation) {
                            processJacksonJsonSerialize(fieldInfo, annotation);
                        }
                        break;
                    case "com.google.gson.annotations.SerializedName":
                        processGsonSerializedName(fieldInfo, annotation);
                        break;
                    default:
                        break;
                }
            }

            if (jsonField == null) {
                return;
            }

            loadFieldInfo(fieldInfo, jsonField);

            Class writeUsing = jsonField.writeUsing();
            if (ObjectWriter.class.isAssignableFrom(writeUsing)) {
                fieldInfo.writeUsing = writeUsing;
            }

            Class serializeUsing = jsonField.serializeUsing();
            if (ObjectWriter.class.isAssignableFrom(serializeUsing)) {
                fieldInfo.writeUsing = serializeUsing;
            }

            if (jsonField.jsonDirect()) {
                fieldInfo.features |= FieldInfo.RAW_VALUE_MASK;
            }

            if ((fieldInfo.features & JSONWriter.Feature.WriteNonStringValueAsString.mask) != 0
                    && !String.class.equals(field.getType())
                    && fieldInfo.writeUsing == null
            ) {
                fieldInfo.writeUsing = ObjectWriterImplToString.class;
            }
        }

        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)) {
                        Annotation[] value = (Annotation[]) 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 item = value[i];
                                processJacksonJsonSubTypesType(beanInfo, i, item);
                            }
                        }
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void processJacksonJsonSerialize(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 "using": {
                            Class using = processUsing((Class) result);
                            if (using != null) {
                                beanInfo.serializer = using;
                            }
                            break;
                        }
                        case "keyUsing":
                            Class keyUsing = processUsing((Class) result);
                            if (keyUsing != null) {
                                beanInfo.serializer = keyUsing;
                            }
                            break;
                        default:
                            break;
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private Class processUsing(Class result) {
            String usingName = result.getName();
            String noneClassName1 = "com.fasterxml.jackson.databind.JsonSerializer$None";
            if (!noneClassName1.equals(usingName)
                    && ObjectWriter.class.isAssignableFrom(result)
            ) {
                return result;
            }

            if ("com.fasterxml.jackson.databind.ser.std.ToStringSerializer".equals(usingName)) {
                return ObjectWriterImplToString.class;
            }
            return null;
        }

        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.writerFeatures |= JSONWriter.Feature.WriteClassName.mask;
                        }
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void processJacksonJsonPropertyOrder(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)) {
                        String[] value = (String[]) result;
                        if (value.length != 0) {
                            beanInfo.orders = value;
                        }
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void processJacksonJsonSerialize(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 "using":
                            Class using = processUsing((Class) result);
                            if (using != null) {
                                fieldInfo.writeUsing = 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.valueUsing = valueUsing;
                            }
                            break;
                        default:
                            break;
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void processJacksonJsonProperty(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;
                        case "access": {
                            String access = ((Enum) result).name();
                            fieldInfo.ignore = "WRITE_ONLY".equals(access);
                            break;
                        }
                        default:
                            break;
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void processJacksonJsonIgnoreProperties(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)) {
                        String[] value = (String[]) result;
                        if (value.length != 0) {
                            beanInfo.ignores = value;
                        }
                    }
                } 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": {
                            loadJsonFieldFormat(fieldInfo, (String) result);
                            break;
                        }
                        case "label": {
                            String value = (String) result;
                            if (!value.isEmpty()) {
                                fieldInfo.label = value;
                            }
                            break;
                        }
                        case "defaultValue": {
                            String value = (String) result;
                            if (!value.isEmpty()) {
                                fieldInfo.defaultValue = value;
                            }
                            break;
                        }
                        case "ordinal": {
                            int ordinal = (Integer) result;
                            if (ordinal != 0) {
                                fieldInfo.ordinal = ordinal;
                            }
                            break;
                        }
                        case "serialize": {
                            boolean serialize = (Boolean) result;
                            if (!serialize) {
                                fieldInfo.ignore = true;
                            }
                            break;
                        }
                        case "unwrapped": {
                            if ((Boolean) result) {
                                fieldInfo.features |= FieldInfo.UNWRAPPED_MASK;
                            }
                            break;
                        }
                        case "serialzeFeatures": {
                            Enum[] features = (Enum[]) result;
                            applyFeatures(fieldInfo, features);
                            break;
                        }
                        case "serializeUsing": {
                            Class writeUsing = (Class) result;
                            if (ObjectWriter.class.isAssignableFrom(writeUsing)) {
                                fieldInfo.writeUsing = writeUsing;
                            }
                            break;
                        }
                        case "jsonDirect": {
                            Boolean jsonDirect = (Boolean) result;
                            if (jsonDirect) {
                                fieldInfo.features |= FieldInfo.RAW_VALUE_MASK;
                            }
                            break;
                        }
                        default:
                            break;
                    }
                } catch (Throwable ignored) {
                    // ignored
                }
            });
        }

        private void applyFeatures(FieldInfo fieldInfo, Enum[] features) {
            for (Enum feature : features) {
                switch (feature.name()) {
                    case "UseISO8601DateFormat":
                        fieldInfo.format = "iso8601";
                        break;
                    case "WriteMapNullValue":
                        fieldInfo.features |= JSONWriter.Feature.WriteNulls.mask;
                        break;
                    case "WriteNullListAsEmpty":
                        fieldInfo.features |= JSONWriter.Feature.WriteNullListAsEmpty.mask;
                        break;
                    case "WriteNullStringAsEmpty":
                        fieldInfo.features |= JSONWriter.Feature.WriteNullStringAsEmpty.mask;
                        break;
                    case "WriteNullNumberAsZero":
                        fieldInfo.features |= JSONWriter.Feature.WriteNullNumberAsZero.mask;
                        break;
                    case "WriteNullBooleanAsFalse":
                        fieldInfo.features |= JSONWriter.Feature.WriteNullBooleanAsFalse.mask;
                        break;
                    case "BrowserCompatible":
                        fieldInfo.features |= JSONWriter.Feature.BrowserCompatible.mask;
                        break;
                    case "WriteClassName":
                        fieldInfo.features |= JSONWriter.Feature.WriteClassName.mask;
                        break;
                    case "WriteNonStringValueAsString":
                        fieldInfo.features |= JSONWriter.Feature.WriteNonStringValueAsString.mask;
                        break;
                    case "WriteEnumUsingToString":
                        fieldInfo.features |= JSONWriter.Feature.WriteEnumUsingToString.mask;
                        break;
                    case "NotWriteRootClassName":
                        fieldInfo.features |= JSONWriter.Feature.NotWriteRootClassName.mask;
                        break;
                    case "IgnoreErrorGetter":
                        fieldInfo.features |= JSONWriter.Feature.IgnoreErrorGetter.mask;
                        break;
                    case "WriteBigDecimalAsPlain":
                        fieldInfo.features |= JSONWriter.Feature.WriteBigDecimalAsPlain.mask;
                        break;
                    default:
                        break;
                }
            }
        }

        @Override
        public void getFieldInfo(BeanInfo beanInfo, FieldInfo fieldInfo, Class objectClass, Method method) {
            Class mixInSource = provider.mixInCache.get(objectClass);
            String methodName = method.getName();

            if ("getTargetSql".equals(methodName)) {
                if (objectClass != null
                        && objectClass.getName().startsWith("com.baomidou.mybatisplus.")
                ) {
                    fieldInfo.features |= JSONWriter.Feature.IgnoreErrorGetter.mask;
                }
            }

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

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

            Class fieldClassMixInSource = provider.mixInCache.get(method.getReturnType());
            if (fieldClassMixInSource != null) {
                fieldInfo.fieldClassMixIn = true;
            }

            if (JDKUtils.CLASS_TRANSIENT != null && method.getAnnotation(JDKUtils.CLASS_TRANSIENT) != null) {
                fieldInfo.ignore = true;
            }

            if (objectClass != null) {
                Class superclass = objectClass.getSuperclass();
                Method supperMethod = BeanUtils.getMethod(superclass, method);
                boolean ignore = fieldInfo.ignore;
                if (supperMethod != null) {
                    getFieldInfo(beanInfo, fieldInfo, superclass, supperMethod);
                    int supperMethodModifiers = supperMethod.getModifiers();
                    if (ignore != fieldInfo.ignore
                            && !Modifier.isAbstract(supperMethodModifiers)
                            && !supperMethod.equals(method)
                    ) {
                        fieldInfo.ignore = ignore;
                    }
                }

                Class[] interfaces = objectClass.getInterfaces();
                for (Class anInterface : interfaces) {
                    Method interfaceMethod = BeanUtils.getMethod(anInterface, method);
                    if (interfaceMethod != null) {
                        getFieldInfo(beanInfo, fieldInfo, superclass, interfaceMethod);
                    }
                }
            }

            Annotation[] annotations = getAnnotations(method);
            processAnnotations(fieldInfo, annotations);

            if (!objectClass.getName().startsWith("java.lang") && !BeanUtils.isRecord(objectClass)) {
                Field methodField = getField(objectClass, method);
                if (methodField != null) {
                    fieldInfo.features |= FieldInfo.FIELD_MASK;
                    getFieldInfo(beanInfo, fieldInfo, objectClass, methodField);
                }
            }

            if (beanInfo.kotlin
                    && beanInfo.creatorConstructor != null
                    && beanInfo.createParameterNames != null
            ) {
                String fieldName = BeanUtils.getterName(method, null);
                for (int i = 0; i < beanInfo.createParameterNames.length; i++) {
                    if (fieldName.equals(beanInfo.createParameterNames[i])) {
                        Annotation[][] creatorConsParamAnnotations
                                = beanInfo.creatorConstructor.getParameterAnnotations();
                        if (i < creatorConsParamAnnotations.length) {
                            Annotation[] parameterAnnotations = creatorConsParamAnnotations[i];
                            processAnnotations(fieldInfo, parameterAnnotations);
                            break;
                        }
                    }
                }
            }
        }

        private void processAnnotations(FieldInfo fieldInfo, Annotation[] annotations) {
            for (Annotation annotation : annotations) {
                Class annotationType = annotation.annotationType();
                JSONField jsonField = findAnnotation(annotation, JSONField.class);
                if (Objects.nonNull(jsonField)) {
                    loadFieldInfo(fieldInfo, jsonField);
                    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":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonIgnore":
                        if (useJacksonAnnotation) {
                            processJacksonJsonIgnore(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonAnyGetter":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonAnyGetter":
                        if (useJacksonAnnotation) {
                            fieldInfo.features |= FieldInfo.UNWRAPPED_MASK;
                        }
                        break;
                    case "com.alibaba.fastjson.annotation.JSONField":
                        processJSONField1x(fieldInfo, annotation);
                        break;
                    case "java.beans.Transient":
                        fieldInfo.ignore = true;
                        fieldInfo.isTransient = true;
                        break;
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonProperty":
                    case "com.fasterxml.jackson.annotation.JsonProperty": {
                        if (useJacksonAnnotation) {
                            processJacksonJsonProperty(fieldInfo, annotation);
                        }
                        break;
                    }
                    case "com.fasterxml.jackson.annotation.JsonFormat":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonFormat":
                        if (useJacksonAnnotation) {
                            processJacksonJsonFormat(fieldInfo, annotation);
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonValue":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonValue":
                        if (useJacksonAnnotation) {
                            fieldInfo.features |= FieldInfo.VALUE_MASK;
                        }
                        break;
                    case "com.fasterxml.jackson.annotation.JsonRawValue":
                    case "com.alibaba.fastjson2.adapter.jackson.annotation.JsonRawValue":
                        if (useJacksonAnnotation) {
                            fieldInfo.features |= FieldInfo.RAW_VALUE_MASK;
                        }
                        break;
                    case "com.alibaba.fastjson2.adapter.jackson.databind.annotation.JsonSerialize":
                    case "com.fasterxml.jackson.databind.annotation.JsonSerialize":
                        if (useJacksonAnnotation) {
                            processJacksonJsonSerialize(fieldInfo, annotation);
                        }
                        break;
                    default:
                        break;
                }
            }
        }

        /**
         * load {@link JSONField} into {@link FieldInfo} params
         *
         * @param fieldInfo Java Field Info
         * @param jsonField {@link JSONField} JSON Field Info
         */
        private void loadFieldInfo(FieldInfo fieldInfo, JSONField jsonField) {
            String jsonFieldName = jsonField.name();
            if (!jsonFieldName.isEmpty()) {
                fieldInfo.fieldName = jsonFieldName;
            }

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

            loadJsonFieldFormat(fieldInfo, jsonField.format());

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

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

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

            for (JSONWriter.Feature feature : jsonField.serializeFeatures()) {
                fieldInfo.features |= feature.mask;
            }

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

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

            if (jsonField.jsonDirect()) {
                fieldInfo.features |= FieldInfo.RAW_VALUE_MASK;
            }

            Class serializeUsing = jsonField.serializeUsing();
            if (ObjectWriter.class.isAssignableFrom(serializeUsing)) {
                fieldInfo.writeUsing = serializeUsing;
            }
        }

        /**
         * load {@link JSONField} format params into FieldInfo
         *
         * @param fieldInfo Java Field Info
         * @param jsonFieldFormat {@link JSONField} format params
         */
        private void loadJsonFieldFormat(FieldInfo fieldInfo, String jsonFieldFormat) {
            if (!jsonFieldFormat.isEmpty()) {
                jsonFieldFormat = jsonFieldFormat.trim();

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

                if (!jsonFieldFormat.isEmpty()) {
                    fieldInfo.format = jsonFieldFormat;
                }
            }
        }
    }

    ObjectWriter getExternalObjectWriter(String className, Class objectClass) {
        switch (className) {
            case "java.sql.Time":
                return JdbcSupport.createTimeWriter(null);
            case "java.sql.Timestamp":
                return JdbcSupport.createTimestampWriter(objectClass, null);
            case "org.joda.time.chrono.GregorianChronology":
                return JodaSupport.createGregorianChronologyWriter(objectClass);
            case "org.joda.time.chrono.ISOChronology":
                return JodaSupport.createISOChronologyWriter(objectClass);
            case "org.joda.time.LocalDate":
                return JodaSupport.createLocalDateWriter(objectClass, null);
            case "org.joda.time.LocalDateTime":
                return JodaSupport.createLocalDateTimeWriter(objectClass, null);
            case "org.joda.time.DateTime":
                return new ObjectWriterImplZonedDateTime(null, null, new JodaSupport.DateTime2ZDT());
            default:
                if (JdbcSupport.isClob(objectClass)) {
                    return JdbcSupport.createClobWriter(objectClass);
                }
                return null;
        }
    }

    @Override
    public ObjectWriter getObjectWriter(Type objectType, Class objectClass) {
        if (objectType == String.class) {
            return ObjectWriterImplString.INSTANCE;
        }

        if (objectClass == null) {
            if (objectType instanceof Class) {
                objectClass = (Class) objectType;
            } else {
                objectClass = TypeUtils.getMapping(objectType);
            }
        }

        String className = objectClass.getName();
        ObjectWriter externalObjectWriter = getExternalObjectWriter(className, objectClass);
        if (externalObjectWriter != null) {
            return externalObjectWriter;
        }

        switch (className) {
            case "com.google.common.collect.AbstractMapBasedMultimap$RandomAccessWrappedList":
            case "com.google.common.collect.AbstractMapBasedMultimap$WrappedSet":
                return null;
            case "org.javamoney.moneta.internal.JDKCurrencyAdapter":
                return ObjectWriterImplToString.INSTANCE;
            case "com.fasterxml.jackson.databind.node.ObjectNode":
                return ObjectWriterImplToString.DIRECT;
            case "org.javamoney.moneta.Money":
                return MoneySupport.createMonetaryAmountWriter();
            case "org.javamoney.moneta.spi.DefaultNumberValue":
                return MoneySupport.createNumberValueWriter();
            case "net.sf.json.JSONNull":
            case "java.net.Inet4Address":
            case "java.net.Inet6Address":
            case "java.net.InetSocketAddress":
            case "java.text.SimpleDateFormat":
            case "java.util.regex.Pattern":
            case "com.fasterxml.jackson.databind.node.ArrayNode":
                return ObjectWriterMisc.INSTANCE;
            case "org.apache.commons.lang3.tuple.Pair":
            case "org.apache.commons.lang3.tuple.MutablePair":
            case "org.apache.commons.lang3.tuple.ImmutablePair":
                return new ApacheLang3Support.PairWriter(objectClass);
            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 "com.carrotsearch.hppc.BitSet":
            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 "gnu.trove.stack.array.TByteArrayStack":
            case "org.bson.types.Decimal128":
                return LambdaMiscCodec.getObjectWriter(objectType, objectClass);
            case "java.nio.HeapByteBuffer":
            case "java.nio.DirectByteBuffer":
                return new ObjectWriterImplInt8ValueArray(
                        o -> ((ByteBuffer) o).array()
                );
            default:
                break;
        }

        if (objectType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) objectType;
            Type rawType = parameterizedType.getRawType();
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

            if (rawType == List.class || rawType == ArrayList.class) {
                if (actualTypeArguments.length == 1
                        && actualTypeArguments[0] == String.class) {
                    return ObjectWriterImplListStr.INSTANCE;
                }

                objectType = rawType;
            }

            if (Map.class.isAssignableFrom(objectClass)) {
                return ObjectWriterImplMap.of(objectType, objectClass);
            }

            if (objectClass == Optional.class) {
                if (actualTypeArguments.length == 1) {
                    return new ObjectWriterImplOptional(actualTypeArguments[0], null, null);
                }
            }
        }

        if (objectType == LinkedList.class) {
            return ObjectWriterImplList.INSTANCE;
        }

        if (objectType == ArrayList.class
                || objectType == List.class
                || List.class.isAssignableFrom(objectClass)) {
            return ObjectWriterImplList.INSTANCE;
        }

        if (Collection.class.isAssignableFrom(objectClass)) {
            return ObjectWriterImplCollection.INSTANCE;
        }

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

        if (Map.class.isAssignableFrom(objectClass)) {
            return ObjectWriterImplMap.of(objectClass);
        }

        if (Map.Entry.class.isAssignableFrom(objectClass)) {
            return ObjectWriterImplMapEntry.INSTANCE;
        }

        if (java.nio.file.Path.class.isAssignableFrom(objectClass)) {
            return ObjectWriterImplToString.INSTANCE;
        }

        if (objectType == Integer.class) {
            return ObjectWriterImplInt32.INSTANCE;
        }

        if (objectType == AtomicInteger.class) {
            return ObjectWriterImplAtomicInteger.INSTANCE;
        }

        if (objectType == Byte.class) {
            return ObjectWriterImplInt8.INSTANCE;
        }

        if (objectType == Short.class) {
            return ObjectWriterImplInt16.INSTANCE;
        }

        if (objectType == Long.class) {
            return ObjectWriterImplInt64.INSTANCE;
        }

        if (objectType == AtomicLong.class) {
            return ObjectWriterImplAtomicLong.INSTANCE;
        }

        if (objectType == AtomicReference.class) {
            return ObjectWriterImplAtomicReference.INSTANCE;
        }

        if (objectType == Float.class) {
            return ObjectWriterImplFloat.INSTANCE;
        }

        if (objectType == Double.class) {
            return ObjectWriterImplDouble.INSTANCE;
        }

        if (objectType == BigInteger.class) {
            return ObjectWriterBigInteger.INSTANCE;
        }

        if (objectType == BigDecimal.class) {
            return ObjectWriterImplBigDecimal.INSTANCE;
        }

        if (objectType == BitSet.class) {
            return ObjectWriterImplBitSet.INSTANCE;
        }

        if (objectType == OptionalInt.class) {
            return ObjectWriterImplOptionalInt.INSTANCE;
        }

        if (objectType == OptionalLong.class) {
            return ObjectWriterImplOptionalLong.INSTANCE;
        }

        if (objectType == OptionalDouble.class) {
            return ObjectWriterImplOptionalDouble.INSTANCE;
        }

        if (objectType == Optional.class) {
            return ObjectWriterImplOptional.INSTANCE;
        }

        if (objectType == Boolean.class) {
            return ObjectWriterImplBoolean.INSTANCE;
        }

        if (objectType == AtomicBoolean.class) {
            return ObjectWriterImplAtomicBoolean.INSTANCE;
        }

        if (objectType == AtomicIntegerArray.class) {
            return ObjectWriterImplAtomicIntegerArray.INSTANCE;
        }

        if (objectType == AtomicLongArray.class) {
            return ObjectWriterImplAtomicLongArray.INSTANCE;
        }

        if (objectType == Character.class) {
            return ObjectWriterImplCharacter.INSTANCE;
        }

        if (objectType instanceof Class) {
            Class clazz = (Class) objectType;

            if (TimeUnit.class.isAssignableFrom(clazz)) {
                return new ObjectWriterImplEnum(null, TimeUnit.class, null, null, 0);
            }

            if (Enum.class.isAssignableFrom(clazz)) {
                ObjectWriter enumWriter = createEnumWriter(clazz);
                if (enumWriter != null) {
                    return enumWriter;
                }
            }

            if (JSONPath.class.isAssignableFrom(clazz)) {
                return ObjectWriterImplToString.INSTANCE;
            }

            if (clazz == boolean[].class) {
                return ObjectWriterImplBoolValueArray.INSTANCE;
            }

            if (clazz == char[].class) {
                return ObjectWriterImplCharValueArray.INSTANCE;
            }

            if (clazz == StringBuffer.class || clazz == StringBuilder.class) {
                return ObjectWriterImplToString.INSTANCE;
            }

            if (clazz == byte[].class) {
                return ObjectWriterImplInt8ValueArray.INSTANCE;
            }

            if (clazz == short[].class) {
                return ObjectWriterImplInt16ValueArray.INSTANCE;
            }

            if (clazz == int[].class) {
                return ObjectWriterImplInt32ValueArray.INSTANCE;
            }

            if (clazz == long[].class) {
                return ObjectWriterImplInt64ValueArray.INSTANCE;
            }

            if (clazz == float[].class) {
                return ObjectWriterImplFloatValueArray.INSTANCE;
            }

            if (clazz == double[].class) {
                return ObjectWriterImplDoubleValueArray.INSTANCE;
            }

            if (clazz == Byte[].class) {
                return ObjectWriterImplInt8Array.INSTANCE;
            }

            if (clazz == Integer[].class) {
                return ObjectWriterImplInt32Array.INSTANCE;
            }

            if (clazz == Long[].class) {
                return ObjectWriterImplInt64Array.INSTANCE;
            }

            if (String[].class == clazz) {
                return ObjectWriterImplStringArray.INSTANCE;
            }

            if (BigDecimal[].class == clazz) {
                return ObjectWriterImpDecimalArray.INSTANCE;
            }

            if (Object[].class.isAssignableFrom(clazz)) {
                if (clazz == Object[].class) {
                    return ObjectWriterArray.INSTANCE;
                } else {
                    Class componentType = clazz.getComponentType();
                    if (Modifier.isFinal(componentType.getModifiers())) {
                        return new ObjectWriterArrayFinal(componentType, null);
                    } else {
                        return new ObjectWriterArray(componentType);
                    }
                }
            }

            if (clazz == UUID.class) {
                return ObjectWriterImplUUID.INSTANCE;
            }

            if (clazz == Locale.class) {
                return ObjectWriterImplLocale.INSTANCE;
            }

            if (clazz == Currency.class) {
                return ObjectWriterImplCurrency.INSTANCE;
            }

            if (TimeZone.class.isAssignableFrom(clazz)) {
                return ObjectWriterImplTimeZone.INSTANCE;
            }

            if (JSONPObject.class.isAssignableFrom(clazz)) {
                return new ObjectWriterImplJSONP();
            }

            if (clazz == URI.class
                    || clazz == URL.class
                    || clazz == File.class
                    || ZoneId.class.isAssignableFrom(clazz)
                    || Charset.class.isAssignableFrom(clazz)) {
                return ObjectWriterImplToString.INSTANCE;
            }

            externalObjectWriter = getExternalObjectWriter(clazz.getName(), clazz);
            if (externalObjectWriter != null) {
                return externalObjectWriter;
            }

            BeanInfo beanInfo = new BeanInfo();
            Class mixIn = provider.getMixIn(clazz);
            if (mixIn != null) {
                annotationProcessor.getBeanInfo(beanInfo, mixIn);
            }

            if (Date.class.isAssignableFrom(clazz)) {
                if (beanInfo.format != null || beanInfo.locale != null) {
                    return new ObjectWriterImplDate(beanInfo.format, beanInfo.locale);
                }

                return ObjectWriterImplDate.INSTANCE;
            }

            if (Calendar.class.isAssignableFrom(clazz)) {
                if (beanInfo.format != null || beanInfo.locale != null) {
                    return new ObjectWriterImplCalendar(beanInfo.format, beanInfo.locale);
                }

                return ObjectWriterImplCalendar.INSTANCE;
            }

            if (ZonedDateTime.class == clazz) {
                if (beanInfo.format != null || beanInfo.locale != null) {
                    return new ObjectWriterImplZonedDateTime(beanInfo.format, beanInfo.locale);
                }

                return ObjectWriterImplZonedDateTime.INSTANCE;
            }

            if (OffsetDateTime.class == clazz) {
                return ObjectWriterImplOffsetDateTime.of(beanInfo.format, beanInfo.locale);
            }

            if (LocalDateTime.class == clazz) {
                if (beanInfo.format != null || beanInfo.locale != null) {
                    return new ObjectWriterImplLocalDateTime(beanInfo.format, beanInfo.locale);
                }

                return ObjectWriterImplLocalDateTime.INSTANCE;
            }

            if (LocalDate.class == clazz) {
                return ObjectWriterImplLocalDate.of(beanInfo.format, beanInfo.locale);
            }

            if (LocalTime.class == clazz) {
                if (beanInfo.format != null || beanInfo.locale != null) {
                    return new ObjectWriterImplLocalTime(beanInfo.format, beanInfo.locale);
                }

                return ObjectWriterImplLocalTime.INSTANCE;
            }

            if (OffsetTime.class == clazz) {
                if (beanInfo.format != null || beanInfo.locale != null) {
                    return new ObjectWriterImplOffsetTime(beanInfo.format, beanInfo.locale);
                }

                return ObjectWriterImplOffsetTime.INSTANCE;
            }

            if (Instant.class == clazz) {
                if (beanInfo.format != null || beanInfo.locale != null) {
                    return new ObjectWriterImplInstant(beanInfo.format, beanInfo.locale);
                }

                return ObjectWriterImplInstant.INSTANCE;
            }

            if (Duration.class == clazz) {
                return ObjectWriterImplToString.INSTANCE;
            }

            if (StackTraceElement.class == clazz) {
                // return createFieldWriter(null, null, fieldName, 0, 0, null, null, fieldClass, fieldClass, null, function);
                if (STACK_TRACE_ELEMENT_WRITER == null) {
                    ObjectWriterCreator creator = provider.getCreator();
                    STACK_TRACE_ELEMENT_WRITER = new ObjectWriterAdapter(
                            StackTraceElement.class,
                            null,
                            null,
                            0,
                            Arrays.asList(
                                    creator.createFieldWriter(
                                            "fileName",
                                            String.class,
                                            BeanUtils.getDeclaredField(StackTraceElement.class, "fileName"),
                                            BeanUtils.getMethod(StackTraceElement.class, "getFileName"),
                                            StackTraceElement::getFileName
                                    ),
                                    creator.createFieldWriter(
                                            "lineNumber",
                                            BeanUtils.getDeclaredField(StackTraceElement.class, "lineNumber"),
                                            BeanUtils.getMethod(StackTraceElement.class, "getLineNumber"),
                                            StackTraceElement::getLineNumber
                                    ),
                                    creator.createFieldWriter(
                                            "className",
                                            String.class,
                                            BeanUtils.getDeclaredField(StackTraceElement.class, "declaringClass"),
                                            BeanUtils.getMethod(StackTraceElement.class, "getClassName"),
                                            StackTraceElement::getClassName
                                    ),
                                    creator.createFieldWriter(
                                            "methodName",
                                            String.class,
                                            BeanUtils.getDeclaredField(StackTraceElement.class, "methodName"),
                                            BeanUtils.getMethod(StackTraceElement.class, "getMethodName"),
                                            StackTraceElement::getMethodName
                                    )
                            )
                    );
                }
                return STACK_TRACE_ELEMENT_WRITER;
            }

            if (Class.class == clazz) {
                return ObjectWriterImplClass.INSTANCE;
            }

            if (Method.class == clazz) {
                return new ObjectWriterAdapter<>(
                        Method.class,
                        null,
                        null,
                        0,
                        Arrays.asList(
                                ObjectWriters.fieldWriter("declaringClass", Class.class, Method::getDeclaringClass),
                                ObjectWriters.fieldWriter("name", String.class, Method::getName),
                                ObjectWriters.fieldWriter("parameterTypes", Class[].class, Method::getParameterTypes)
                        )
                );
            }

            if (Field.class == clazz) {
                return new ObjectWriterAdapter<>(
                        Method.class,
                        null,
                        null,
                        0,
                        Arrays.asList(
                                ObjectWriters.fieldWriter("declaringClass", Class.class, Field::getDeclaringClass),
                                ObjectWriters.fieldWriter("name", String.class, Field::getName)
                        )
                );
            }

            if (ParameterizedType.class.isAssignableFrom(clazz)) {
                return ObjectWriters.objectWriter(
                        ParameterizedType.class,
                        ObjectWriters.fieldWriter("actualTypeArguments", Type[].class, ParameterizedType::getActualTypeArguments),
                        ObjectWriters.fieldWriter("ownerType", Type.class, ParameterizedType::getOwnerType),
                        ObjectWriters.fieldWriter("rawType", Type.class, ParameterizedType::getRawType)
                );
            }
        }

        return null;
    }

    private ObjectWriter createEnumWriter(Class enumClass) {
        if (!enumClass.isEnum()) {
            Class superclass = enumClass.getSuperclass();
            if (superclass.isEnum()) {
                enumClass = superclass;
            }
        }

        Member valueField = BeanUtils.getEnumValueField(enumClass, provider);
        if (valueField == null) {
            Class mixInSource = provider.mixInCache.get(enumClass);
            Member mixedValueField = BeanUtils.getEnumValueField(mixInSource, provider);
            if (mixedValueField instanceof Field) {
                try {
                    valueField = enumClass.getField(mixedValueField.getName());
                } catch (NoSuchFieldException ignored) {
                }
            } else if (mixedValueField instanceof Method) {
                try {
                    valueField = enumClass.getMethod(mixedValueField.getName());
                } catch (NoSuchMethodException ignored) {
                }
            }
        }

        BeanInfo beanInfo = new BeanInfo();

        Class[] interfaces = enumClass.getInterfaces();
        for (int i = 0; i < interfaces.length; i++) {
            annotationProcessor.getBeanInfo(beanInfo, interfaces[i]);
        }

        annotationProcessor.getBeanInfo(beanInfo, enumClass);
        if (beanInfo.writeEnumAsJavaBean) {
            return null;
        }

        String[] annotationNames = BeanUtils.getEnumAnnotationNames(enumClass);
        return new ObjectWriterImplEnum(null, enumClass, valueField, annotationNames, 0);
    }

    static class VoidObjectWriter
            implements ObjectWriter {
        public static final VoidObjectWriter INSTANCE = new VoidObjectWriter();

        @Override
        public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy