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

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

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

import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.codec.FieldInfo;
import com.alibaba.fastjson2.util.BeanUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicLongArray;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import static com.alibaba.fastjson2.JSONWriter.Feature.*;
import static com.alibaba.fastjson2.util.BeanUtils.SUPER;

public class FieldWriterObject
        extends FieldWriter {
    volatile Class initValueClass;
    final boolean unwrapped;
    final boolean array;
    final boolean number;

    static final AtomicReferenceFieldUpdater initValueClassUpdater = AtomicReferenceFieldUpdater.newUpdater(
            FieldWriterObject.class,
            Class.class,
            "initValueClass"
    );

    protected FieldWriterObject(
            String name,
            int ordinal,
            long features,
            String format,
            String label,
            Type fieldType,
            Class fieldClass,
            Field field,
            Method method
    ) {
        super(name, ordinal, features, format, label, fieldType, fieldClass, field, method);
        this.unwrapped = (features & FieldInfo.UNWRAPPED_MASK) != 0;

        if (fieldClass == Currency.class) {
            this.initValueClass = fieldClass;
            this.initObjectWriter = ObjectWriterImplCurrency.INSTANCE_FOR_FIELD;
        }

        array = fieldClass.isArray()
                || Collection.class.isAssignableFrom(fieldClass)
                || fieldClass == AtomicLongArray.class
                || fieldClass == AtomicIntegerArray.class;
        number = Number.class.isAssignableFrom(fieldClass);
    }

    @Override
    public ObjectWriter getInitWriter() {
        return initObjectWriter;
    }

    @Override
    public boolean unwrapped() {
        return unwrapped;
    }

    @Override
    public ObjectWriter getObjectWriter(JSONWriter jsonWriter, Class valueClass) {
        final Class initValueClass = this.initValueClass;
        if (initValueClass == null || initObjectWriter == ObjectWriterBaseModule.VoidObjectWriter.INSTANCE) {
            return getObjectWriterVoid(jsonWriter, valueClass);
        } else {
            boolean typeMatch = initValueClass == valueClass
                    || (initValueClass == Map.class && initValueClass.isAssignableFrom(valueClass))
                    || (initValueClass == List.class && initValueClass.isAssignableFrom(valueClass));
            if (!typeMatch && initValueClass.isPrimitive()) {
                typeMatch = typeMatch(initValueClass, valueClass);
            }

            if (typeMatch) {
                ObjectWriter objectWriter;
                if (initObjectWriter == null) {
                    objectWriter = getObjectWriterTypeMatch(jsonWriter, valueClass);
                } else {
                    objectWriter = initObjectWriter;
                }
                return objectWriter;
            } else {
                return getObjectWriterTypeNotMatch(jsonWriter, valueClass);
            }
        }
    }

    private ObjectWriter getObjectWriterVoid(JSONWriter jsonWriter, Class valueClass) {
        ObjectWriter formattedWriter = null;
        if (BeanUtils.isExtendedMap(valueClass) && SUPER.equals(fieldName)) {
            JSONWriter.Context context = jsonWriter.context;
            boolean fieldBased = ((features | context.getFeatures()) & JSONWriter.Feature.FieldBased.mask) != 0;
            formattedWriter = context.provider.getObjectWriter(fieldType, fieldClass, fieldBased);
            if (initObjectWriter == null) {
                boolean success = initValueClassUpdater.compareAndSet(this, null, valueClass);
                if (success) {
                    initObjectWriterUpdater.compareAndSet(this, null, formattedWriter);
                }
            }
            return formattedWriter;
        }

        if (format == null) {
            JSONWriter.Context context = jsonWriter.context;
            boolean fieldBased = ((features | context.getFeatures()) & JSONWriter.Feature.FieldBased.mask) != 0;
            formattedWriter = context.provider.getObjectWriterFromCache(valueClass, valueClass, fieldBased);
        }

        final DecimalFormat decimalFormat = this.decimalFormat;
        if (valueClass == Float[].class) {
            if (decimalFormat != null) {
                formattedWriter = new ObjectWriterArrayFinal(Float.class, decimalFormat);
            } else {
                formattedWriter = ObjectWriterArrayFinal.FLOAT_ARRAY;
            }
        } else if (valueClass == Double[].class) {
            if (decimalFormat != null) {
                formattedWriter = new ObjectWriterArrayFinal(Double.class, decimalFormat);
            } else {
                formattedWriter = ObjectWriterArrayFinal.DOUBLE_ARRAY;
            }
        } else if (valueClass == float[].class) {
            if (decimalFormat != null) {
                formattedWriter = new ObjectWriterImplFloatValueArray(decimalFormat);
            } else {
                formattedWriter = ObjectWriterImplFloatValueArray.INSTANCE;
            }
        } else if (valueClass == double[].class) {
            if (decimalFormat != null) {
                formattedWriter = new ObjectWriterImplDoubleValueArray(decimalFormat);
            } else {
                formattedWriter = ObjectWriterImplDoubleValueArray.INSTANCE;
            }
        }

        if (formattedWriter == null) {
            formattedWriter = FieldWriter.getObjectWriter(fieldType, fieldClass, format, null, valueClass);
        }

        if (formattedWriter == null) {
            boolean success = initValueClassUpdater.compareAndSet(this, null, valueClass);
            formattedWriter = jsonWriter.getObjectWriter(valueClass);
            if (success) {
                initObjectWriterUpdater.compareAndSet(this, null, formattedWriter);
            }
        } else {
            if (initObjectWriter == null) {
                boolean success = initValueClassUpdater.compareAndSet(this, null, valueClass);
                if (success) {
                    initObjectWriterUpdater.compareAndSet(this, null, formattedWriter);
                }
            }
        }
        return formattedWriter;
    }

    static boolean typeMatch(Class initValueClass, Class valueClass) {
        return (initValueClass == int.class && valueClass == Integer.class)
                || (initValueClass == long.class && valueClass == Long.class)
                || (initValueClass == boolean.class && valueClass == Boolean.class)
                || (initValueClass == short.class && valueClass == Short.class)
                || (initValueClass == byte.class && valueClass == Byte.class)
                || (initValueClass == float.class && valueClass == Float.class)
                || (initValueClass == double.class && valueClass == Double.class)
                || (initValueClass == char.class && valueClass == Character.class);
    }

    private ObjectWriter getObjectWriterTypeNotMatch(JSONWriter jsonWriter, Class valueClass) {
        if (Map.class.isAssignableFrom(valueClass)) {
            if (fieldClass.isAssignableFrom(valueClass)) {
                return ObjectWriterImplMap.of(fieldType, valueClass);
            } else {
                return ObjectWriterImplMap.of(valueClass);
            }
        } else {
            ObjectWriter objectWriter = null;
            if (format != null) {
                objectWriter = FieldWriter.getObjectWriter(fieldType, fieldClass, format, null, valueClass);
            }
            if (objectWriter == null) {
                objectWriter = jsonWriter.getObjectWriter(valueClass);
            }
            return objectWriter;
        }
    }

    private ObjectWriter getObjectWriterTypeMatch(JSONWriter jsonWriter, Class valueClass) {
        ObjectWriter objectWriter;
        if (Map.class.isAssignableFrom(valueClass)) {
            if (fieldClass.isAssignableFrom(valueClass)) {
                objectWriter = ObjectWriterImplMap.of(fieldType, valueClass);
            } else {
                objectWriter = ObjectWriterImplMap.of(valueClass);
            }
        } else {
            objectWriter = jsonWriter.getObjectWriter(valueClass);
        }
        initObjectWriterUpdater.compareAndSet(this, null, objectWriter);
        return objectWriter;
    }

    @Override
    public void writeEnumJSONB(JSONWriter jsonWriter, Enum e) {
        if (e == null) {
            return;
        }

        writeFieldName(jsonWriter);

        Class valueClass = e.getClass();
        ObjectWriter valueWriter;
        if (initValueClass == null) {
            initValueClass = valueClass;
            valueWriter = jsonWriter.getObjectWriter(valueClass);
            initObjectWriterUpdater.compareAndSet(this, null, valueWriter);
        } else {
            if (initValueClass == valueClass) {
                valueWriter = initObjectWriter;
            } else {
                valueWriter = jsonWriter.getObjectWriter(valueClass);
            }
        }
        if (valueWriter == null) {
            throw new JSONException("get value writer error, valueType : " + valueClass);
        }

        valueWriter.writeJSONB(jsonWriter, e, fieldName, fieldType, this.features);
    }

    @Override
    public boolean write(JSONWriter jsonWriter, T object) {
        long features = this.features | jsonWriter.getFeatures();

        if (!fieldClassSerializable && (features & JSONWriter.Feature.IgnoreNoneSerializable.mask) != 0) {
            return false;
        }

        Object value;
        try {
            value = getFieldValue(object);
        } catch (RuntimeException error) {
            if (jsonWriter.isIgnoreErrorGetter()) {
                return false;
            }
            throw error;
        }

        // (features & JSONWriter.Feature.WriteNullNumberAsZero.mask) != 0
        if (value == null) {
            if ((features & WriteNulls.mask) != 0 && (features & NotWriteDefaultValue.mask) == 0) {
                writeFieldName(jsonWriter);
                if (array) {
                    jsonWriter.writeArrayNull();
                } else if (number) {
                    jsonWriter.writeNumberNull();
                } else if (fieldClass == Appendable.class
                        || fieldClass == StringBuffer.class
                        || fieldClass == StringBuilder.class) {
                    jsonWriter.writeStringNull();
                } else {
                    jsonWriter.writeNull();
                }
                return true;
            } else {
                if ((features & (WriteNullNumberAsZero.mask | NullAsDefaultValue.mask)) != 0 && number) {
                    writeFieldName(jsonWriter);
                    jsonWriter.writeInt32(0);
                    return true;
                } else if ((features & (WriteNullBooleanAsFalse.mask | NullAsDefaultValue.mask)) != 0
                        && (fieldClass == Boolean.class || fieldClass == AtomicBoolean.class)
                ) {
                    writeFieldName(jsonWriter);
                    jsonWriter.writeBool(false);
                    return true;
                }
                return false;
            }
        }

        if (value == object) {
            if (fieldClass == Throwable.class
                    && field != null
                    && field.getDeclaringClass() == Throwable.class
            ) {
                return false;
            }
        }

        if ((features & JSONWriter.Feature.IgnoreNoneSerializable.mask) != 0 && !(value instanceof Serializable)) {
            return false;
        }

        boolean refDetect = jsonWriter.isRefDetect(value);
        if (refDetect) {
            if (value == object) {
                writeFieldName(jsonWriter);
                jsonWriter.writeReference("..");
                return true;
            }

            String refPath = jsonWriter.setPath(this, value);
            if (refPath != null) {
                writeFieldName(jsonWriter);
                jsonWriter.writeReference(refPath);
                jsonWriter.popPath(value);
                return true;
            }
        }

        Class valueClass = value.getClass();
        if (valueClass == byte[].class) {
            writeBinary(jsonWriter, (byte[]) value);
            return true;
        }

        ObjectWriter valueWriter = getObjectWriter(jsonWriter, valueClass);
        if (valueWriter == null) {
            throw new JSONException("get objectWriter error : " + valueClass);
        }

        if (unwrapped) {
            if (value instanceof Map) {
                for (Map.Entry entry : (Iterable) ((Map) value).entrySet()) {
                    String entryKey = entry.getKey().toString();
                    Object entryValue = entry.getValue();
                    if (entryValue == null) {
                        if ((features & WriteNulls.mask) == 0) {
                            continue;
                        }
                    }

                    jsonWriter.writeName(entryKey);
                    jsonWriter.writeColon();
                    if (entryValue == null) {
                        jsonWriter.writeNull();
                    } else {
                        Class entryValueClass = entryValue.getClass();
                        ObjectWriter entryValueWriter = jsonWriter.getObjectWriter(entryValueClass);
                        entryValueWriter.write(jsonWriter, entryValue);
                    }
                }

                if (refDetect) {
                    jsonWriter.popPath(value);
                }
                return true;
            }

            if (valueWriter instanceof ObjectWriterAdapter) {
                ObjectWriterAdapter writerAdapter = (ObjectWriterAdapter) valueWriter;
                List fieldWriters = writerAdapter.fieldWriters;
                for (FieldWriter fieldWriter : fieldWriters) {
                    fieldWriter.write(jsonWriter, value);
                }
                return true;
            }
        }

        writeFieldName(jsonWriter);
        boolean jsonb = jsonWriter.jsonb;
        if ((this.features & JSONWriter.Feature.BeanToArray.mask) != 0) {
            if (jsonb) {
                valueWriter.writeArrayMappingJSONB(jsonWriter, value, fieldName, fieldType, this.features);
            } else {
                valueWriter.writeArrayMapping(jsonWriter, value, fieldName, fieldType, this.features);
            }
        } else {
            if (jsonb) {
                valueWriter.writeJSONB(jsonWriter, value, fieldName, fieldType, this.features);
            } else {
                valueWriter.write(jsonWriter, value, fieldName, fieldType, this.features);
            }
        }

        if (refDetect) {
            jsonWriter.popPath(value);
        }
        return true;
    }

    @Override
    public void writeValue(JSONWriter jsonWriter, T object) {
        Object value = getFieldValue(object);
        if (value == null) {
            jsonWriter.writeNull();
            return;
        }

        Class valueClass = value.getClass();
        ObjectWriter valueWriter;
        if (initValueClass == null) {
            initValueClass = valueClass;
            valueWriter = jsonWriter.getObjectWriter(valueClass);
            initObjectWriterUpdater.compareAndSet(this, null, valueWriter);
        } else {
            if (initValueClass == valueClass) {
                valueWriter = initObjectWriter;
            } else {
                valueWriter = jsonWriter.getObjectWriter(valueClass);
            }
        }
        if (valueWriter == null) {
            throw new JSONException("get value writer error, valueType : " + valueClass);
        }

        boolean refDetect = jsonWriter.isRefDetect() && !ObjectWriterProvider.isNotReferenceDetect(valueClass);

        if (refDetect) {
            if (value == object) {
                jsonWriter.writeReference("..");
                return;
            }

            String refPath = jsonWriter.setPath(fieldName, value);
            if (refPath != null) {
                jsonWriter.writeReference(refPath);
                jsonWriter.popPath(value);
                return;
            }
        }

        if (jsonWriter.jsonb) {
            if (jsonWriter.isBeanToArray()) {
                valueWriter.writeArrayMappingJSONB(jsonWriter, value, fieldName, fieldClass, features);
            } else {
                valueWriter.writeJSONB(jsonWriter, value, fieldName, fieldClass, features);
            }
        } else {
            valueWriter.write(jsonWriter, value, fieldName, fieldClass, features);
        }

        if (refDetect) {
            jsonWriter.popPath(value);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy