private void genReadFieldValue()

in core/src/main/java/com/alibaba/fastjson2/reader/ObjectReaderCreatorASM.java [3041:3572]


    private <T> void genReadFieldValue(
            ObjectReadContext context,
            FieldReader fieldReader,
            boolean fieldBased,
            MethodWriterContext mwc,
            int OBJECT,
            int fieldReaderIndex,
            boolean arrayMapping
    ) {
        String classNameType = context.classNameType;
        boolean jsonb = mwc.jsonb;
        Class objectClass = context.objectClass;
        Class fieldClass = fieldReader.fieldClass;
        Type fieldType = fieldReader.fieldType;
        long fieldFeatures = fieldReader.features;
        String format = fieldReader.format;
        Type itemType = fieldReader.itemType;

        MethodWriter mw = mwc.mw;

        if ((fieldFeatures & JSONReader.Feature.NullOnError.mask) != 0) {
            mw.aload(THIS);
            mw.getfield(classNameType, fieldReader(fieldReaderIndex), DESC_FIELD_READER);
            mw.aload(JSON_READER);
            mw.aload(OBJECT);
            mw.invokevirtual(TYPE_FIELD_READE, "readFieldValue", METHOD_DESC_READ_FIELD_VALUE);
            return;
        }

        Field field = fieldReader.field;
        Method method = fieldReader.method;

        Label endSet_ = new Label();

        String TYPE_FIELD_CLASS = ASMUtils.type(fieldClass);
        String DESC_FIELD_CLASS = ASMUtils.desc(fieldClass);

        if (!(context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor)) {
            mw.aload(OBJECT);
        }
        int fieldModifier = 0;
        if ((fieldBased || method == null) && field != null) {
            fieldModifier = field.getModifiers();
        }

        if (fieldBased
                && Modifier.isPublic(objectClass.getModifiers())
                && Modifier.isPublic(fieldModifier)
                && !Modifier.isFinal(fieldModifier)
                && !classLoader.isExternalClass(objectClass)
        ) {
            mw.checkcast(context.objectType);
        }

        if (fieldClass == boolean.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readBoolValue", "()Z");
        } else if (fieldClass == byte.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt32Value", "()I");
        } else if (fieldClass == short.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt32Value", "()I");
        } else if (fieldClass == int.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt32Value", "()I");
        } else if (fieldClass == long.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt64Value", "()J");
        } else if (fieldClass == float.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readFloatValue", "()F");
        } else if (fieldClass == double.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readDoubleValue", "()D");
        } else if (fieldClass == char.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readCharValue", "()C");
        } else if (fieldClass == String.class) {
            mw.aload(JSON_READER);
            Label null_ = new Label();

            mw.invokevirtual(TYPE_JSON_READER, "readString", "()Ljava/lang/String;");
            mw.dup();
            mw.ifnull(null_);

            if ("trim".equals(format)) {
                mw.invokevirtual("java/lang/String", "trim", "()Ljava/lang/String;");
            } else if ("upper".equals(format)) {
                mw.invokevirtual("java/lang/String", "toUpperCase", "()Ljava/lang/String;");
            }
            mw.visitLabel(null_);
        } else if (fieldClass == Boolean.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readBool", "()Ljava/lang/Boolean;");
        } else if (fieldClass == Byte.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt8", "()Ljava/lang/Byte;");
        } else if (fieldClass == Short.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt16", "()Ljava/lang/Short;");
        } else if (fieldClass == Integer.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt32", "()Ljava/lang/Integer;");
        } else if (fieldClass == Long.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt64", "()Ljava/lang/Long;");
        } else if (fieldClass == Float.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readFloat", "()Ljava/lang/Float;");
        } else if (fieldClass == Double.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readDouble", "()Ljava/lang/Double;");
        } else if (fieldClass == BigDecimal.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readBigDecimal", "()Ljava/math/BigDecimal;");
        } else if (fieldClass == BigInteger.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readBigInteger", "()Ljava/math/BigInteger;");
        } else if (fieldClass == Number.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readNumber", "()Ljava/lang/Number;");
        } else if (fieldClass == UUID.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readUUID", "()Ljava/util/UUID;");
        } else if (fieldClass == LocalDate.class && fieldReader.format == null) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readLocalDate", "()Ljava/time/LocalDate;");
        } else if (fieldClass == OffsetDateTime.class && fieldReader.format == null) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readOffsetDateTime", "()Ljava/time/OffsetDateTime;");
        } else if (fieldClass == Date.class && fieldReader.format == null) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readDate", "()Ljava/util/Date;");
        } else if (fieldClass == Calendar.class && fieldReader.format == null) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readCalendar", "()Ljava/util/Calendar;");
        } else {
            Label endObject_ = new Label();

            boolean disableReferenceDetect = context.disableReferenceDetect();
            Integer REFERENCE = null;
            if (!disableReferenceDetect) {
                REFERENCE = mwc.var("REFERENCE");
            }

            if ((!disableReferenceDetect) && (!ObjectWriterProvider.isPrimitiveOrEnum(fieldClass))) {
                Label endReference_ = new Label(), addResolveTask_ = new Label();

                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "isReference", "()Z");
                mw.ifeq(endReference_);

                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "readReference", "()Ljava/lang/String;");
                if (context.objectClass == null || fieldClass.isAssignableFrom(context.objectClass)) {
                    mw.dup();
                    mw.astore(REFERENCE);
                    mw.visitLdcInsn("..");
                    mw.invokevirtual("java/lang/String", "equals", "(Ljava/lang/Object;)Z");
                    mw.ifeq(addResolveTask_);

                    if (objectClass != null && fieldClass.isAssignableFrom(objectClass)) {
                        mw.aload(OBJECT);
//                    mw.visitTypeInsn(CHECKCAST, TYPE_FIELD_CLASS); // cast
                        mw.goto_(endObject_);
                    }

                    mw.visitLabel(addResolveTask_);
                } else {
                    mw.astore(REFERENCE);
                }

                mw.aload(THIS);
                mw.getfield(classNameType, fieldReader(fieldReaderIndex), DESC_FIELD_READER);
                mw.aload(JSON_READER);
                mw.aload(OBJECT);
                mw.aload(REFERENCE);
                mw.invokevirtual(TYPE_FIELD_READE, "addResolveTask", METHOD_DESC_ADD_RESOLVE_TASK);
                mw.pop();
                mw.goto_(endSet_);

                mw.visitLabel(endReference_);
            }

            if (!fieldReader.fieldClassSerializable) {
                Label endIgnoreCheck_ = new Label();

                /*
                 * if ((features & Feature.IgnoreNoneSerializable.mask) != 0) {
                 *     jsonReader.skipValue();
                 *     goto endSet_;
                 * }
                 */
                mw.lload(FEATURES);
                mw.visitLdcInsn(JSONReader.Feature.IgnoreNoneSerializable.mask);
                mw.land();
                mw.lconst_0();
                mw.lcmp();
                mw.ifeq(endIgnoreCheck_);

                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "skipValue", "()V");
                if (!(context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor)) {
                    mw.pop();
                }
                mw.goto_(endSet_);

                mw.visitLabel(endIgnoreCheck_);
            }

            boolean list = List.class.isAssignableFrom(fieldClass)
                    && fieldReader.getInitReader() == null
                    && !fieldClass.getName().startsWith("com.google.common.collect.Immutable");

            if (list) {
                Class itemClass = TypeUtils.getMapping(itemType);
                if (itemClass != null
                        && (Collection.class.isAssignableFrom(itemClass) || !Modifier.isPublic(itemClass.getModifiers()))
                ) {
                    list = false;
                }
            }

            if (list && !fieldClass.isInterface() && !BeanUtils.hasPublicDefaultConstructor(fieldClass)) {
                list = false;
            }

            if (list) {
                genReadFieldValueList(
                        fieldReader,
                        classNameType,
                        mwc,
                        OBJECT,
                        fieldReaderIndex,
                        arrayMapping,
                        objectClass,
                        fieldClass,
                        fieldType,
                        fieldFeatures,
                        itemType,
                        TYPE_FIELD_CLASS,
                        context,
                        fieldBased
                );
            } else {
                final String FIELD_OBJECT_READER = fieldObjectReader(fieldReaderIndex);

                Label valueNotNull_ = new Label();

                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "nextIfNull", "()Z");
                mw.ifeq(valueNotNull_);

                if (fieldClass == Optional.class) {
                    mw.invokestatic("java/util/Optional", "empty", "()Ljava/util/Optional;");
                } else if (fieldClass == OptionalInt.class) {
                    mw.invokestatic("java/util/OptionalInt", "empty", "()Ljava/util/OptionalInt;");
                } else if (fieldClass == OptionalLong.class) {
                    mw.invokestatic("java/util/OptionalLong", "empty", "()Ljava/util/OptionalLong;");
                } else if (fieldClass == OptionalDouble.class) {
                    mw.invokestatic("java/util/OptionalDouble", "empty", "()Ljava/util/OptionalDouble;");
                } else {
                    mw.aconst_null();
                }
                mw.goto_(endObject_);

                mw.visitLabel(valueNotNull_);

                if (fieldClass == String[].class) {
                    mw.aload(JSON_READER);
                    mw.invokevirtual(TYPE_JSON_READER, "readStringArray", "()[Ljava/lang/String;");
                } else if (fieldClass == int[].class) {
                    mw.aload(JSON_READER);
                    mw.invokevirtual(TYPE_JSON_READER, "readInt32ValueArray", "()[I");
                } else if (fieldClass == long[].class) {
                    mw.aload(JSON_READER);
                    mw.invokevirtual(TYPE_JSON_READER, "readInt64ValueArray", "()[J");
                } else {
                    if (Enum.class.isAssignableFrom(fieldClass) & !jsonb) {
                        genReadEnumValueRaw(
                                fieldReader,
                                classNameType,
                                mwc,
                                fieldReaderIndex,
                                fieldType,
                                fieldClass,
                                fieldFeatures,
                                FIELD_OBJECT_READER
                        );
                    } else {
                        genReadObject(
                                fieldReader,
                                classNameType,
                                mwc,
                                fieldReaderIndex,
                                fieldType,
                                fieldFeatures,
                                FIELD_OBJECT_READER
                        );
                    }

                    if (method != null
                            || ((objectClass == null || Modifier.isPublic(objectClass.getModifiers()))
                            && Modifier.isPublic(fieldModifier)
                            && !Modifier.isFinal(fieldModifier)
                            && !classLoader.isExternalClass(objectClass))
                    ) {
                        mw.checkcast(TYPE_FIELD_CLASS); // cast
                    }

                    if (fieldReader.noneStaticMemberClass) {
                        try {
                            Field this0 = fieldClass.getDeclaredField("this$0");
                            long fieldOffset = UNSAFE.objectFieldOffset(this0);

                            Label notNull_ = new Label();
                            mw.dup();
                            mw.ifnull(notNull_);
                            mw.dup();
                            mw.getstatic(TYPE_UNSAFE_UTILS, "UNSAFE", "Lsun/misc/Unsafe;");
                            mw.swap();
                            mw.visitLdcInsn(fieldOffset);
                            mw.aload(OBJECT);
                            mw.invokevirtual("sun/misc/Unsafe", "putObject", "(Ljava/lang/Object;JLjava/lang/Object;)V");
                            mw.visitLabel(notNull_);
                        } catch (NoSuchFieldException e) {
                            // ignored
                        }
                    }
                }
            }

            mw.visitLabel(endObject_);
        }

        if (field != null) {
            String fieldClassName = fieldClass.getName();
            boolean setDirect = (objectClass.getModifiers() & Modifier.PUBLIC) != 0
                    && (fieldModifier & Modifier.PUBLIC) != 0
                    && (fieldModifier & Modifier.FINAL) == 0
                    && (ObjectWriterProvider.isPrimitiveOrEnum(fieldClass) || fieldClassName.startsWith("java.") || fieldClass.getClassLoader() == ObjectReaderProvider.FASTJSON2_CLASS_LOADER)
                    && !classLoader.isExternalClass(objectClass)
                    && field.getDeclaringClass() == objectClass;
            if (setDirect) {
                mw.putfield(context.objectType, field.getName(), DESC_FIELD_CLASS);
            } else {
                int FIELD_VALUE = mwc.var(fieldClass);

                String methodName, methodDes;
                int LOAD;
                if (fieldClass == int.class) {
                    methodName = "putInt";
                    methodDes = "(Ljava/lang/Object;JI)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == long.class) {
                    methodName = "putLong";
                    methodDes = "(Ljava/lang/Object;JJ)V";
                    mw.lstore(FIELD_VALUE);
                    LOAD = Opcodes.LLOAD;
                } else if (fieldClass == float.class) {
                    methodName = "putFloat";
                    methodDes = "(Ljava/lang/Object;JF)V";
                    mw.fstore(FIELD_VALUE);
                    LOAD = Opcodes.FLOAD;
                } else if (fieldClass == double.class) {
                    methodName = "putDouble";
                    methodDes = "(Ljava/lang/Object;JD)V";
                    mw.dstore(FIELD_VALUE);
                    LOAD = Opcodes.DLOAD;
                } else if (fieldClass == char.class) {
                    methodName = "putChar";
                    methodDes = "(Ljava/lang/Object;JC)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == byte.class) {
                    methodName = "putByte";
                    methodDes = "(Ljava/lang/Object;JB)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == short.class) {
                    methodName = "putShort";
                    methodDes = "(Ljava/lang/Object;JS)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == boolean.class) {
                    methodName = "putBoolean";
                    methodDes = "(Ljava/lang/Object;JZ)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else {
                    methodName = "putObject";
                    methodDes = "(Ljava/lang/Object;JLjava/lang/Object;)V";
                    mw.astore(FIELD_VALUE);
                    LOAD = Opcodes.ALOAD;
                }

                mw.getstatic(TYPE_UNSAFE_UTILS, "UNSAFE", "Lsun/misc/Unsafe;");
                mw.swap();

                mw.visitLdcInsn(
                        UNSAFE.objectFieldOffset(field));
                mw.visitVarInsn(LOAD, FIELD_VALUE);
                mw.invokevirtual("sun/misc/Unsafe", methodName, methodDes);
            }
        } else if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
            if (!fieldClass.isPrimitive()) {
                mw.checkcast(ASMUtils.type(fieldClass));
            }
            mw.storeLocal(fieldClass, mwc.var(fieldReader));
        } else {
            boolean invokeFieldReaderAccept = context.externalClass || method == null || !context.publicClass;

            if (invokeFieldReaderAccept) {
                int FIELD_VALUE = mwc.var(fieldClass);

                String acceptMethodDesc;
                int LOAD;
                if (fieldClass == boolean.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;Z)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == byte.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;B)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == short.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;S)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == int.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;I)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == long.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;J)V";
                    mw.lstore(FIELD_VALUE);
                    LOAD = Opcodes.LLOAD;
                } else if (fieldClass == char.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;C)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == float.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;F)V";
                    mw.fstore(FIELD_VALUE);
                    LOAD = Opcodes.FLOAD;
                } else if (fieldClass == double.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;D)V";
                    mw.dstore(FIELD_VALUE);
                    LOAD = Opcodes.DLOAD;
                } else {
                    acceptMethodDesc = "(Ljava/lang/Object;Ljava/lang/Object;)V";
                    mw.astore(FIELD_VALUE);
                    LOAD = Opcodes.ALOAD;
                }

                mw.aload(THIS);
                mw.getfield(classNameType, fieldReader(fieldReaderIndex), DESC_FIELD_READER);
                BiConsumer function = fieldReader.getFunction();
                if (function instanceof FieldBiConsumer) {
                    FieldBiConsumer fieldBiConsumer = (FieldBiConsumer) function;
                    mw.invokevirtual(TYPE_FIELD_READE, "getFunction", "()Ljava/util/function/BiConsumer;");
                    mw.checkcast(type(FieldBiConsumer.class));
                    mw.getfield(type(FieldBiConsumer.class), "consumer", desc(FieldConsumer.class));
                    mw.swap();
                    mw.visitLdcInsn(fieldBiConsumer.fieldIndex);
                    mw.visitVarInsn(LOAD, FIELD_VALUE);
                    mw.invokeinterface(type(FieldConsumer.class), "accept", "(Ljava/lang/Object;ILjava/lang/Object;)V");
                } else {
                    mw.swap();
                    mw.visitVarInsn(LOAD, FIELD_VALUE);
                    mw.invokevirtual(TYPE_FIELD_READE, "accept", acceptMethodDesc);
                }
            } else {
                Class<?> returnType = method.getReturnType();
                String methodName = method.getName();

                String methodDesc = null;
                if (returnType == Void.TYPE) {
                    if (fieldClass == boolean.class) {
                        methodDesc = "(Z)V";
                    } else if (fieldClass == byte.class) {
                        methodDesc = "(B)V";
                    } else if (fieldClass == short.class) {
                        methodDesc = "(S)V";
                    } else if (fieldClass == int.class) {
                        methodDesc = "(I)V";
                    } else if (fieldClass == long.class) {
                        methodDesc = "(J)V";
                    } else if (fieldClass == char.class) {
                        methodDesc = "(C)V";
                    } else if (fieldClass == float.class) {
                        methodDesc = "(F)V";
                    } else if (fieldClass == double.class) {
                        methodDesc = "(D)V";
                    } else if (fieldClass == Boolean.class) {
                        methodDesc = "(Ljava/lang/Boolean;)V";
                    } else if (fieldClass == Integer.class) {
                        methodDesc = "(Ljava/lang/Integer;)V";
                    } else if (fieldClass == Long.class) {
                        methodDesc = "(Ljava/lang/Long;)V";
                    } else if (fieldClass == Float.class) {
                        methodDesc = "(Ljava/lang/Float;)V";
                    } else if (fieldClass == Double.class) {
                        methodDesc = "(Ljava/lang/Double;)V";
                    } else if (fieldClass == BigDecimal.class) {
                        methodDesc = "(Ljava/math/BigDecimal;)V";
                    } else if (fieldClass == String.class) {
                        methodDesc = "(Ljava/lang/String;)V";
                    } else if (fieldClass == UUID.class) {
                        methodDesc = "(Ljava/util/UUID;)V";
                    } else if (fieldClass == List.class) {
                        methodDesc = "(Ljava/util/List;)V";
                    } else if (fieldClass == Map.class) {
                        methodDesc = "(Ljava/util/Map;)V";
                    }
                }

                if (methodDesc == null) {
                    methodDesc = "(" + DESC_FIELD_CLASS + ")" + ASMUtils.desc(returnType);
                }
                mw.invokevirtual(context.objectType, methodName, methodDesc);
                if (returnType != void.class) {
                    mw.pop();
                }
            }
            // TODO BUILD METHOD
        }

        mw.visitLabel(endSet_);
    }