public ObjectWriter createObjectWriter()

in core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreator.java [315:606]


    public ObjectWriter createObjectWriter(
            final Class objectClass,
            final long features,
            final ObjectWriterProvider provider
    ) {
        BeanInfo beanInfo = provider.createBeanInfo();
        beanInfo.readerFeatures |= FieldInfo.JIT;

        provider.getBeanInfo(beanInfo, objectClass);

        if (beanInfo.serializer != null && ObjectWriter.class.isAssignableFrom(beanInfo.serializer)) {
            try {
                return (ObjectWriter) beanInfo.serializer.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new JSONException("create serializer error", e);
            }
        }

        boolean record = BeanUtils.isRecord(objectClass);

        long beanFeatures = beanInfo.writerFeatures;
        if (beanInfo.seeAlso != null) {
            beanFeatures &= ~JSONWriter.Feature.WriteClassName.mask;
        }

        long writerFieldFeatures = features | beanFeatures;
        boolean fieldBased = (writerFieldFeatures & JSONWriter.Feature.FieldBased.mask) != 0;

        if (fieldBased && (record || objectClass.isInterface())) {
            fieldBased = false;
        }

        List<FieldWriter> fieldWriters;
        final FieldInfo fieldInfo = new FieldInfo();

        if (fieldBased) {
            Map<String, FieldWriter> fieldWriterMap = new TreeMap<>();
            BeanUtils.declaredFields(objectClass, field -> {
                fieldInfo.init();
                FieldWriter fieldWriter = creteFieldWriter(objectClass, writerFieldFeatures, provider, beanInfo, fieldInfo, field);
                if (fieldWriter != null) {
                    fieldWriterMap.put(fieldWriter.fieldName, fieldWriter);
                }
            });
            fieldWriters = new ArrayList<>(fieldWriterMap.values());
        } else {
            boolean fieldWritersCreated = false;
            fieldWriters = new ArrayList<>();
            for (ObjectWriterModule module : provider.modules) {
                if (module.createFieldWriters(this, objectClass, fieldWriters)) {
                    fieldWritersCreated = true;
                    break;
                }
            }

            if (!fieldWritersCreated) {
                Map<String, FieldWriter> fieldWriterMap = new TreeMap<>();

                if (!record) {
                    BeanUtils.declaredFields(objectClass, field -> {
                        fieldInfo.init();
                        fieldInfo.ignore = (field.getModifiers() & Modifier.PUBLIC) == 0;
                        FieldWriter fieldWriter = creteFieldWriter(objectClass, writerFieldFeatures, provider, beanInfo, fieldInfo, field);
                        if (fieldWriter != null) {
                            FieldWriter origin = fieldWriterMap.putIfAbsent(fieldWriter.fieldName, fieldWriter);

                            if (origin != null && origin.compareTo(fieldWriter) > 0) {
                                fieldWriterMap.put(fieldWriter.fieldName, fieldWriter);
                            }
                        }
                    });
                }

                Class mixIn = provider.getMixIn(objectClass);

                BeanUtils.getters(objectClass, mixIn, beanInfo.kotlin, method -> {
                    fieldInfo.init();
                    fieldInfo.features = writerFieldFeatures;
                    fieldInfo.format = beanInfo.format;
                    provider.getFieldInfo(beanInfo, fieldInfo, objectClass, method);
                    if (fieldInfo.ignore) {
                        return;
                    }

                    String fieldName = getFieldName(objectClass, provider, beanInfo, record, fieldInfo, method);

                    if (beanInfo.includes != null && beanInfo.includes.length > 0) {
                        boolean match = false;
                        for (String include : beanInfo.includes) {
                            if (include.equals(fieldName)) {
                                match = true;
                                break;
                            }
                        }
                        if (!match) {
                            return;
                        }
                    }

                    // skip typeKey field
                    if ((beanInfo.writerFeatures & WriteClassName.mask) != 0
                            && fieldName.equals(beanInfo.typeKey)) {
                        return;
                    }

                    if (beanInfo.orders != null) {
                        boolean match = false;
                        for (int i = 0; i < beanInfo.orders.length; i++) {
                            if (fieldName.equals(beanInfo.orders[i])) {
                                fieldInfo.ordinal = i;
                                match = true;
                            }
                        }
                        if (!match) {
                            if (fieldInfo.ordinal == 0) {
                                fieldInfo.ordinal = beanInfo.orders.length;
                            }
                        }
                    }

                    Class<?> returnType = method.getReturnType();
                    // skip function
                    if (isFunction(returnType)) {
                        return;
                    }

                    ObjectWriter writeUsingWriter = null;
                    if (fieldInfo.writeUsing != null) {
                        try {
                            Constructor<?> constructor = fieldInfo.writeUsing.getDeclaredConstructor();
                            constructor.setAccessible(true);
                            writeUsingWriter = (ObjectWriter) constructor.newInstance();
                        } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                                 NoSuchMethodException e) {
                            throw new JSONException("create writeUsing Writer error", e);
                        }
                    }

                    if (writeUsingWriter == null && fieldInfo.fieldClassMixIn) {
                        writeUsingWriter = ObjectWriterBaseModule.VoidObjectWriter.INSTANCE;
                    }

                    FieldWriter fieldWriter = null;
                    if ((beanInfo.readerFeatures & FieldInfo.JIT) != 0) {
                        try {
                            fieldWriter = createFieldWriterLambda(
                                    provider,
                                    objectClass,
                                    fieldName,
                                    fieldInfo.ordinal,
                                    fieldInfo.features,
                                    fieldInfo.format,
                                    fieldInfo.label,
                                    method,
                                    writeUsingWriter,
                                    fieldInfo.contentAs
                            );
                        } catch (Throwable ignored) {
                            jitErrorCount.incrementAndGet();
                            jitErrorLast = ignored;
                        }
                    }
                    if (fieldWriter == null) {
                        fieldWriter = createFieldWriter(
                                provider,
                                objectClass,
                                fieldName,
                                fieldInfo.ordinal,
                                fieldInfo.features,
                                fieldInfo.format,
                                fieldInfo.locale,
                                fieldInfo.label,
                                method,
                                writeUsingWriter,
                                fieldInfo.contentAs
                        );
                    }

                    FieldWriter origin = fieldWriterMap.putIfAbsent(fieldWriter.fieldName, fieldWriter);

                    if (origin != null && origin.compareTo(fieldWriter) > 0) {
                        fieldWriterMap.put(fieldName, fieldWriter);
                    }

                    // the sameFieldName means only differ in first character that one is upper case the other is lower case
                    if (origin == null) {
                        String sameFieldName = null;
                        char firstChar = fieldName.charAt(0);
                        if (firstChar >= 'A' && firstChar <= 'Z') {
                            sameFieldName = (char) (firstChar + 32) + fieldName.substring(1);
                        } else if (firstChar >= 'a' && firstChar <= 'z') {
                            sameFieldName = (char) (firstChar - 32) + fieldName.substring(1);
                        }
                        if (sameFieldName != null) {
                            fieldWriterMap.remove(sameFieldName);
                        }
                    }
                });

                fieldWriters = new ArrayList<>(fieldWriterMap.values());
            }
        }

        long writerFeatures = features | beanInfo.writerFeatures;
        if ((!fieldBased) && Throwable.class.isAssignableFrom(objectClass)) {
            return new ObjectWriterException(objectClass, writerFeatures, fieldWriters);
        }

        handleIgnores(beanInfo, fieldWriters);

        if (beanInfo.alphabetic) {
            Collections.sort(fieldWriters);
        }

        if (BeanUtils.isExtendedMap(objectClass)) {
            Type superType = objectClass.getGenericSuperclass();
            FieldWriter superWriter = ObjectWriters.fieldWriter(
                    SUPER,
                    superType,
                    objectClass.getSuperclass(),
                    Function.identity()
            );
            fieldWriters.add(superWriter);
        }

        setDefaultValue(fieldWriters, objectClass);

        ObjectWriterAdapter writerAdapter = null;

        boolean googleCollection;
        String typeName = objectClass.getName();
        googleCollection =
                "com.google.common.collect.AbstractMapBasedMultimap$RandomAccessWrappedList".equals(typeName)
                        || "com.google.common.collect.AbstractMapBasedMultimap$WrappedSet".equals(typeName);
        if (!googleCollection && beanInfo.rootName == null) {
            switch (fieldWriters.size()) {
                case 1:
                    if ((fieldWriters.get(0).features & FieldInfo.VALUE_MASK) == 0) {
                        writerAdapter = new ObjectWriter1(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    }
                    break;
                case 2:
                    writerAdapter = new ObjectWriter2(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    break;
                case 3:
                    writerAdapter = new ObjectWriter3(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    break;
                case 4:
                    writerAdapter = new ObjectWriter4(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    break;
                case 5:
                    writerAdapter = new ObjectWriter5(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    break;
                case 6:
                    writerAdapter = new ObjectWriter6(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    break;
                case 7:
                    writerAdapter = new ObjectWriter7(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    break;
                case 8:
                    writerAdapter = new ObjectWriter8(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    break;
                case 9:
                    writerAdapter = new ObjectWriter9(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    break;
                case 10:
                    writerAdapter = new ObjectWriter10(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    break;
                case 11:
                    writerAdapter = new ObjectWriter11(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    break;
                case 12:
                    writerAdapter = new ObjectWriter12(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
                    break;
                default:
                    break;
            }
        }
        if (writerAdapter == null) {
            if (beanInfo.rootName != null) {
                writerAdapter = new ObjectWriterRootName(objectClass, beanInfo.typeKey, beanInfo.typeName, beanInfo.rootName, writerFeatures, fieldWriters);
            } else {
                writerAdapter = new ObjectWriterAdapter(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
            }
        }

        if (beanInfo.serializeFilters != null) {
            configSerializeFilters(beanInfo, writerAdapter);
        }

        return writerAdapter;
    }