public ObjectWriter createObjectWriter()

in core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java [159:448]


    public ObjectWriter createObjectWriter(
            Class objectClass,
            long features,
            ObjectWriterProvider provider
    ) {
        int modifiers = objectClass.getModifiers();
        boolean externalClass = classLoader.isExternalClass(objectClass);
        boolean publicClass = Modifier.isPublic(modifiers);

        BeanInfo beanInfo = provider.createBeanInfo();
        provider.getBeanInfo(beanInfo, objectClass);

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

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

        boolean record = BeanUtils.isRecord(objectClass);
        long writerFieldFeatures = features | beanFeatures | (record ? FieldInfo.RECORD : 0);
        final boolean fieldBased = ((writerFieldFeatures & JSONWriter.Feature.FieldBased.mask) != 0 && !objectClass.isInterface())
                || !beanInfo.alphabetic;

        if (Throwable.class.isAssignableFrom(objectClass)
                || BeanUtils.isExtendedMap(objectClass)
                || beanInfo.rootName != null
        ) {
            return super.createObjectWriter(objectClass, features, provider);
        }

        List<FieldWriter> fieldWriters;
        Map<String, FieldWriter> fieldWriterMap = new LinkedHashMap<>();
        if (!fieldBased || record) {
            List<FieldWriter> fieldWriterList = new ArrayList<>();
            boolean fieldWritersCreated = false;
            for (ObjectWriterModule module : provider.modules) {
                if (module.createFieldWriters(this, objectClass, fieldWriterList)) {
                    fieldWritersCreated = true;
                    break;
                }
            }

            if (fieldWritersCreated) {
                for (FieldWriter fieldWriter : fieldWriterList) {
                    Method method = fieldWriter.method;
                    if (method == null) {
                        return super.createObjectWriter(objectClass, writerFieldFeatures, provider);
                    }
                    fieldWriterMap.putIfAbsent(fieldWriter.fieldName, fieldWriter);
                }
            } else {
                final FieldInfo fieldInfo = new FieldInfo();

                if (!record) {
                    BeanUtils.declaredFields(objectClass, field -> {
                        fieldInfo.init();
                        fieldInfo.ignore = ((field.getModifiers() & Modifier.PUBLIC) == 0 || (field.getModifiers() & Modifier.TRANSIENT) != 0);

                        FieldWriter fieldWriter = creteFieldWriter(objectClass, writerFieldFeatures, provider, beanInfo, fieldInfo, field);
                        if (fieldWriter != null) {
                            FieldWriter origin = fieldWriterMap.putIfAbsent(fieldWriter.fieldName, fieldWriter);
                            if (origin != null) {
                                int cmp = origin.compareTo(fieldWriter);
                                if (cmp > 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.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;
                            }
                        }
                    }

                    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;
                    }

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

                    method.setAccessible(true);

                    ObjectWriter writeUsingWriter = null;
                    if (fieldInfo.writeUsing != null) {
                        try {
                            Constructor<?> constructor = fieldInfo.writeUsing.getDeclaredConstructor();
                            constructor.setAccessible(true);
                            writeUsingWriter = (ObjectWriter) constructor.newInstance();
                        } catch (Exception e) {
                            throw new JSONException("create writeUsing Writer error, method " + method.getName()
                                    + ", serializer "
                                    + fieldInfo.writeUsing.getName(), e
                            );
                        }
                    }

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

                    FieldWriter fieldWriter = null;
                    boolean jit = (fieldInfo.features & FieldInfo.JIT) != 0;
                    if (jit) {
                        try {
                            fieldWriter = createFieldWriterLambda(
                                    provider,
                                    objectClass,
                                    fieldName,
                                    fieldInfo.ordinal,
                                    fieldInfo.features,
                                    fieldInfo.format,
                                    fieldInfo.label,
                                    method,
                                    writeUsingWriter,
                                    fieldInfo.contentAs
                            );
                        } catch (Throwable e) {
                            jitErrorCount.incrementAndGet();
                            jitErrorLast = e;
                        }
                    }
                    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(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);
                        }
                    }
                });
            }
        } else {
            final FieldInfo fieldInfo = new FieldInfo();
            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());

        handleIgnores(beanInfo, fieldWriters);
        if (beanInfo.alphabetic) {
            try {
                Collections.sort(fieldWriters);
            } catch (Exception e) {
                StringBuilder msg = new StringBuilder("fieldWriters sort error, objectClass ")
                        .append(objectClass.getName())
                        .append(", fields ");

                JSONArray array = new JSONArray();
                for (FieldWriter fieldWriter : fieldWriters) {
                    array.add(
                            JSONObject.of(
                                    "name", fieldWriter.fieldName,
                                    "type", fieldWriter.fieldClass,
                                    "ordinal", fieldWriter.ordinal,
                                    "field", fieldWriter.field,
                                    "method", fieldWriter.method
                            )
                    );
                }
                msg.append(array);
                throw new JSONException(msg.toString(), e);
            }
        }

        boolean match = fieldWriters.size() < 100 && !Throwable.class.isAssignableFrom(objectClass);

        if (!publicClass || externalClass) {
            for (FieldWriter fieldWriter : fieldWriters) {
                if (fieldWriter.method != null) {
                    match = false;
                    break;
                }
            }
        }

        for (FieldWriter fieldWriter : fieldWriters) {
            if (fieldWriter.getInitWriter() != null
                    || (fieldWriter.features & FieldInfo.VALUE_MASK) != 0
                    || (fieldWriter.features & FieldInfo.RAW_VALUE_MASK) != 0
            ) {
                match = false;
                break;
            }
        }

        if (objectClass.getSuperclass() == Object.class) {
            String simpleName = objectClass.getSimpleName();
            if (simpleName.indexOf('$') != -1 && simpleName.contains("$$")) {
                match = false;
            }
        }
        if (fieldWriters.size() > 64) {
            match = false;
        }

        long writerFeatures = features | beanInfo.writerFeatures;
        if (!match) {
            return super.createObjectWriter(objectClass, features, provider);
        }

        setDefaultValue(fieldWriters, objectClass);

        return jitWriter(objectClass, provider, beanInfo, fieldWriters, writerFeatures);
    }