shade.com.alibaba.fastjson2.reader.FieldReader Maven / Gradle / Ivy
package com.alibaba.fastjson2.reader;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONFactory;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONPath;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.PropertyNamingStrategy;
import com.alibaba.fastjson2.annotation.JSONField;
import com.alibaba.fastjson2.codec.FieldInfo;
import com.alibaba.fastjson2.schema.JSONSchema;
import com.alibaba.fastjson2.util.BeanUtils;
import com.alibaba.fastjson2.util.Fnv;
import com.alibaba.fastjson2.util.JDKUtils;
import com.alibaba.fastjson2.util.JdbcSupport;
import com.alibaba.fastjson2.util.TypeUtils;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
import static com.alibaba.fastjson2.util.JDKUtils.*;
public abstract class FieldReader
implements Comparable {
public final int ordinal;
public final String fieldName;
public final Class fieldClass;
public final Type fieldType;
public final long features;
public final String format;
public final Method method;
public final Field field;
protected final long fieldOffset;
public final Object defaultValue;
public final Locale locale;
public final JSONSchema schema;
final boolean fieldClassSerializable;
final long fieldNameHash;
final long fieldNameHashLCase;
volatile ObjectReader reader;
volatile JSONPath referenceCache;
final boolean noneStaticMemberClass;
final boolean readOnly;
Type itemType;
Class itemClass;
volatile ObjectReader itemReader;
public FieldReader(
String fieldName,
Type fieldType,
Class fieldClass,
int ordinal,
long features,
String format,
Locale locale,
Object defaultValue,
JSONSchema schema,
Method method,
Field field
) {
this.fieldName = fieldName;
this.fieldType = fieldType;
this.fieldClass = fieldClass;
this.fieldClassSerializable = fieldClass != null && (Serializable.class.isAssignableFrom(fieldClass)
|| Modifier.isInterface(fieldClass.getModifiers()));
this.features = features;
this.fieldNameHash = Fnv.hashCode64(fieldName);
this.fieldNameHashLCase = Fnv.hashCode64LCase(fieldName);
this.ordinal = ordinal;
this.format = format;
this.locale = locale;
this.defaultValue = defaultValue;
this.schema = schema;
this.method = method;
this.field = field;
boolean readOnly = false;
if (method != null && method.getParameterCount() == 0) {
readOnly = true;
} else if (field != null && Modifier.isFinal(field.getModifiers())) {
readOnly = true;
}
this.readOnly = readOnly;
long fieldOffset = -1L;
if (field != null && (features & FieldInfo.DISABLE_UNSAFE) == 0) {
fieldOffset = UNSAFE.objectFieldOffset(field);
}
this.fieldOffset = fieldOffset;
if (fieldOffset == -1 && field != null && method == null) {
try {
field.setAccessible(true);
} catch (Throwable e) {
JDKUtils.setReflectErrorLast(e);
}
}
Class declaringClass = null;
if (method != null) {
declaringClass = method.getDeclaringClass();
} else if (field != null) {
declaringClass = field.getDeclaringClass();
}
this.noneStaticMemberClass = BeanUtils.isNoneStaticMemberClass(declaringClass, fieldClass);
}
public void acceptDefaultValue(T object) {
if (defaultValue != null) {
accept(object, defaultValue);
}
}
public ObjectReader getObjectReader(JSONReader jsonReader) {
if (reader != null) {
return reader;
}
return reader = jsonReader.getObjectReader(fieldType);
}
public ObjectReader getObjectReader(JSONReader.Context context) {
if (reader != null) {
return reader;
}
return reader = context.getObjectReader(fieldType);
}
public ObjectReader getObjectReader(ObjectReaderProvider provider) {
if (reader != null) {
return reader;
}
boolean fieldBased = (this.features & JSONReader.Feature.FieldBased.mask) != 0;
return reader = provider.getObjectReader(fieldType, fieldBased);
}
public Type getItemType() {
return itemType;
}
public Class getItemClass() {
if (itemType == null) {
return null;
}
if (itemClass == null) {
itemClass = TypeUtils.getClass(itemType);
}
return itemClass;
}
public long getItemClassHash() {
Class itemClass = getItemClass();
if (itemClass == null) {
return 0;
}
return Fnv.hashCode64(itemClass.getName());
}
@Override
public String toString() {
Member member = this.method != null ? this.method : this.field;
if (member != null) {
return member.getName();
}
return fieldName;
}
public void addResolveTask(JSONReader jsonReader, Object object, String reference) {
JSONPath path;
if (referenceCache != null && referenceCache.toString().equals(reference)) {
path = referenceCache;
} else {
path = referenceCache = JSONPath.of(reference);
}
jsonReader.addResolveTask(this, object, path);
}
@Override
public int compareTo(FieldReader o) {
int nameCompare = this.fieldName.compareTo(o.fieldName);
if (nameCompare != 0) {
if (this.ordinal < o.ordinal) {
return -1;
}
if (this.ordinal > o.ordinal) {
return 1;
}
return nameCompare;
}
int cmp = (isReadOnly() == o.isReadOnly()) ? 0 : (isReadOnly() ? 1 : -1);
if (cmp != 0) {
return cmp;
}
Member thisMember = this.field != null ? this.field : this.method;
Member otherMember = o.field != null ? o.field : o.method;
if (thisMember != null && otherMember != null && thisMember.getClass() != otherMember.getClass()) {
Class otherDeclaringClass = otherMember.getDeclaringClass();
Class thisDeclaringClass = thisMember.getDeclaringClass();
if (thisDeclaringClass != otherDeclaringClass
) {
if (thisDeclaringClass.isAssignableFrom(otherDeclaringClass)) {
return 1;
} else if (otherDeclaringClass.isAssignableFrom(thisDeclaringClass)) {
return -1;
}
}
}
if (this.field != null && o.field != null) {
Class> thisDeclaringClass = this.field.getDeclaringClass();
Class> otherDeclaringClass = o.field.getDeclaringClass();
for (Class s = thisDeclaringClass.getSuperclass(); s != null && s != Object.class; s = s.getSuperclass()) {
if (s == otherDeclaringClass) {
return 1;
}
}
for (Class s = otherDeclaringClass.getSuperclass(); s != null && s != Object.class; s = s.getSuperclass()) {
if (s == thisDeclaringClass) {
return -1;
}
}
}
if (this.method != null && o.method != null) {
Class> thisDeclaringClass = this.method.getDeclaringClass();
Class> otherDeclaringClass = o.method.getDeclaringClass();
for (Class s = thisDeclaringClass.getSuperclass(); s != null && s != Object.class; s = s.getSuperclass()) {
if (s == otherDeclaringClass) {
return -1;
}
}
for (Class s = otherDeclaringClass.getSuperclass(); s != null && s != Object.class; s = s.getSuperclass()) {
if (s == thisDeclaringClass) {
return 1;
}
}
if (this.method.getParameterCount() == 1 && o.method.getParameterCount() == 1) {
Class> thisParamType = this.method.getParameterTypes()[0];
Class> otherParamType = o.method.getParameterTypes()[0];
if (thisParamType != otherParamType) {
if (thisParamType.isAssignableFrom(otherParamType)) {
return 1;
}
if (otherParamType.isAssignableFrom(thisParamType)) {
return -1;
}
if (thisParamType.isEnum() && (otherParamType == Integer.class || otherParamType == int.class)) {
return 1;
}
if (otherParamType.isEnum() && (thisParamType == Integer.class || thisParamType == int.class)) {
return -1;
}
JSONField thisAnnotation = BeanUtils.findAnnotation(this.method, JSONField.class);
JSONField otherAnnotation = BeanUtils.findAnnotation(o.method, JSONField.class);
if (thisAnnotation != null && otherAnnotation == null) {
return -1;
}
if (thisAnnotation == null && otherAnnotation != null) {
return 1;
}
}
}
String thisMethodName = this.method.getName();
String otherMethodName = o.method.getName();
if (!thisMethodName.equals(otherMethodName)) {
String thisName = BeanUtils.setterName(thisMethodName, null);
String otherName = BeanUtils.setterName(otherMethodName, null);
if (this.fieldName.equals(thisName) && !o.fieldName.equals(otherName)) {
return 1;
}
if (o.fieldName.equals(otherName) && !this.fieldName.equals(thisName)) {
return -1;
}
}
}
ObjectReader thisInitReader = this.getInitReader();
ObjectReader otherInitReader = o.getInitReader();
if (thisInitReader != null && otherInitReader == null) {
return -1;
}
if (thisInitReader == null && otherInitReader != null) {
return 1;
}
Class thisFieldClass = this.fieldClass;
Class otherClass = o.fieldClass;
boolean thisClassPrimitive = thisFieldClass.isPrimitive();
boolean otherClassPrimitive = otherClass.isPrimitive();
if (thisClassPrimitive && !otherClassPrimitive) {
return -1;
}
if (!thisClassPrimitive && otherClassPrimitive) {
return 1;
}
boolean thisClassStartsWithJava = thisFieldClass.getName().startsWith("java.");
boolean otherClassStartsWithJava = otherClass.getName().startsWith("java.");
if (thisClassStartsWithJava && !otherClassStartsWithJava) {
return -1;
}
if (!thisClassStartsWithJava && otherClassStartsWithJava) {
return 1;
}
return cmp;
}
public boolean isUnwrapped() {
return (features & FieldInfo.UNWRAPPED_MASK) != 0;
}
public void addResolveTask(JSONReader jsonReader, List object, int i, String reference) {
jsonReader.addResolveTask(object, i, JSONPath.of(reference));
}
public void readFieldValueJSONB(JSONReader jsonReader, T object) {
readFieldValue(jsonReader, object);
}
public abstract Object readFieldValue(JSONReader jsonReader);
public void accept(T object, boolean value) {
accept(object, Boolean.valueOf(value));
}
public boolean supportAcceptType(Class valueClass) {
return fieldClass == valueClass;
}
public void accept(T object, byte value) {
accept(object, Byte.valueOf(value));
}
public void accept(T object, short value) {
accept(object, Short.valueOf(value));
}
public void accept(T object, int value) {
accept(object, Integer.valueOf(value));
}
public void accept(T object, long value) {
accept(object, Long.valueOf(value));
}
public void accept(T object, char value) {
accept(object, Character.valueOf(value));
}
public void accept(T object, float value) {
accept(object, Float.valueOf(value));
}
public void accept(T object, double value) {
accept(object, Double.valueOf(value));
}
public abstract void accept(T object, Object value);
protected void acceptAny(T object, Object fieldValue, long features) {
ObjectReaderProvider provider = JSONFactory.getDefaultObjectReaderProvider();
boolean autoCast = true;
if (fieldValue != null) {
Class> valueClass = fieldValue.getClass();
if (!supportAcceptType(valueClass)) {
if (valueClass == String.class) {
if (fieldClass == Date.class) {
autoCast = false;
}
} else if (valueClass == Integer.class
&& (fieldClass == boolean.class || fieldClass == Boolean.class)
&& (features & JSONReader.Feature.NonZeroNumberCastToBooleanAsTrue.mask) != 0
) {
int intValue = ((Integer) fieldValue);
fieldValue = intValue != 0;
}
if (valueClass != fieldClass && autoCast) {
Function typeConvert = provider.getTypeConvert(valueClass, fieldClass);
if (typeConvert != null) {
fieldValue = typeConvert.apply(fieldValue);
}
}
}
}
Object typedFieldValue;
if (fieldValue == null || fieldType == fieldValue.getClass()) {
typedFieldValue = fieldValue;
} else {
if (fieldValue instanceof JSONObject) {
JSONReader.Feature[] toFeatures = (features & JSONReader.Feature.SupportSmartMatch.mask) != 0
? new JSONReader.Feature[] {JSONReader.Feature.SupportSmartMatch}
: new JSONReader.Feature[0];
typedFieldValue = ((JSONObject) fieldValue).to(fieldType, toFeatures);
} else if (fieldValue instanceof JSONArray) {
typedFieldValue = ((JSONArray) fieldValue).to(fieldType);
} else if (features == 0 && !fieldClass.isInstance(fieldValue) && format == null) {
ObjectReader initReader = getInitReader();
if (initReader != null) {
String fieldValueJson = JSON.toJSONString(fieldValue);
typedFieldValue = initReader.readObject(JSONReader.of(fieldValueJson), fieldType, fieldName, features);
} else {
typedFieldValue = TypeUtils.cast(fieldValue, fieldClass, provider);
}
} else {
if (autoCast) {
String fieldValueJSONString = JSON.toJSONString(fieldValue);
JSONReader.Context readContext = JSONFactory.createReadContext(features);
try (JSONReader jsonReader = JSONReader.of(fieldValueJSONString, readContext)) {
ObjectReader fieldObjectReader = getObjectReader(jsonReader);
typedFieldValue = fieldObjectReader.readObject(jsonReader, null, fieldName, features);
}
} else {
typedFieldValue = fieldValue;
}
}
}
accept(object, typedFieldValue);
}
public abstract void readFieldValue(JSONReader jsonReader, T object);
public ObjectReader checkObjectAutoType(JSONReader jsonReader) {
return null;
}
public boolean isReadOnly() {
return readOnly;
}
public ObjectReader getInitReader() {
return null;
}
public void processExtra(JSONReader jsonReader, Object object) {
jsonReader.skipValue();
}
public void acceptExtra(Object object, String name, Object value) {
}
public ObjectReader getItemObjectReader(JSONReader.Context ctx) {
if (itemReader != null) {
return itemReader;
}
return itemReader = ctx.getObjectReader(itemType);
}
public ObjectReader getItemObjectReader(JSONReader jsonReader) {
return getItemObjectReader(jsonReader.getContext());
}
static ObjectReader createFormattedObjectReader(Type fieldType, Class fieldClass, String format, Locale locale) {
if (format != null && !format.isEmpty()) {
String typeName = fieldType.getTypeName();
switch (typeName) {
case "java.sql.Time":
return JdbcSupport.createTimeReader((Class) fieldType, format, locale);
case "java.sql.Timestamp":
return JdbcSupport.createTimestampReader((Class) fieldType, format, locale);
case "java.sql.Date":
return JdbcSupport.createDateReader((Class) fieldType, format, locale);
case "byte[]":
case "[B":
return new ObjectReaderImplInt8Array(format);
default:
if (Calendar.class.isAssignableFrom(fieldClass)) {
return ObjectReaderImplCalendar.of(format, locale);
}
if (fieldClass == ZonedDateTime.class) {
return ObjectReaderImplZonedDateTime.of(format, locale);
}
if (fieldClass == LocalDateTime.class) {
return new ObjectReaderImplLocalDateTime(format, locale);
}
if (fieldClass == LocalDate.class) {
return ObjectReaderImplLocalDate.of(format, locale);
}
if (fieldClass == LocalTime.class) {
return new ObjectReaderImplLocalTime(format, locale);
}
if (fieldClass == Instant.class) {
return ObjectReaderImplInstant.of(format, locale);
}
if (fieldClass == Optional.class) {
return ObjectReaderImplOptional.of(fieldType, format, locale);
}
if (fieldClass == Date.class) {
return ObjectReaderImplDate.of(format, locale);
}
break;
}
}
return null;
}
public BiConsumer getFunction() {
return null;
}
public boolean sameTo(FieldReader other) {
if (this.field != null) {
String thisName = this.field.getName();
if (other.field != null) {
String otherName = other.field.getName();
if (thisName.equals(otherName)) {
return true;
}
}
if (other.method != null) {
String otherName = getActualFieldName(other);
if (thisName.equals(otherName)) {
return true;
}
}
}
if (this.method != null) {
String thisName = getActualFieldName(this);
if (other.method != null) {
String otherName = getActualFieldName(other);
if (thisName != null && thisName.equals(otherName)) {
return true;
}
}
if (other.field != null) {
return thisName != null && thisName.equals(other.field.getName());
}
}
return false;
}
public boolean belongTo(Class clazz) {
return (this.field != null && this.field.getDeclaringClass() == clazz)
|| (this.method != null && this.method.getDeclaringClass().isAssignableFrom(clazz));
}
private String getActualFieldName(FieldReader fieldReader) {
String name = fieldReader.method.getName();
return fieldReader.isReadOnly() ? BeanUtils.getterName(name, PropertyNamingStrategy.CamelCase.name()) : BeanUtils.setterName(name, PropertyNamingStrategy.CamelCase.name());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy