FieldReader.java
package com.alibaba.fastjson2.reader;
import com.alibaba.fastjson2.JSONPath;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.codec.FieldInfo;
import com.alibaba.fastjson2.schema.JSONSchema;
import com.alibaba.fastjson2.util.*;
import java.io.Serializable;
import java.lang.reflect.*;
import java.time.*;
import java.util.*;
public abstract class FieldReader<T>
implements Comparable<FieldReader> {
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) {
this(
fieldName,
fieldType,
TypeUtils.getClass(fieldType),
0,
0L,
null,
null,
null,
null,
null,
null
);
}
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 && JDKUtils.UNSAFE_SUPPORT && (features & FieldInfo.DISABLE_UNSAFE) == 0) {
fieldOffset = UnsafeUtils.objectFieldOffset(field);
}
this.fieldOffset = fieldOffset;
if (fieldOffset == -1 && field != null && method == null) {
try {
field.setAccessible(true);
} catch (Throwable ignored) {
JDKUtils.setReflectErrorLast(ignored);
}
}
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 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 && thisDeclaringClass != null && otherDeclaringClass != null) {
if (thisDeclaringClass.isAssignableFrom(otherDeclaringClass)) {
return 1;
} else if (otherDeclaringClass.isAssignableFrom(thisDeclaringClass)) {
return -1;
}
}
}
if (this.field != null && o.field != null) {
Class<?> thisFieldDeclaringClass = this.field.getDeclaringClass();
Class<?> otherFieldDeclaringClass = o.field.getDeclaringClass();
for (Class superClass = thisFieldDeclaringClass.getSuperclass(); superClass != null && superClass != Object.class; superClass = superClass.getSuperclass()) {
if (superClass == otherFieldDeclaringClass) {
return 1;
}
}
for (Class superClass = otherFieldDeclaringClass.getSuperclass(); superClass != null && superClass != Object.class; superClass = superClass.getSuperclass()) {
if (superClass == thisFieldDeclaringClass) {
return -1;
}
}
}
if (this.method != null && o.method != null) {
Class<?> thisMethodDeclaringClass = this.method.getDeclaringClass();
Class<?> otherMethodDeclaringClass = o.method.getDeclaringClass();
for (Class superClass = thisMethodDeclaringClass.getSuperclass(); superClass != null && superClass != Object.class; superClass = superClass.getSuperclass()) {
if (superClass == otherMethodDeclaringClass) {
return -1;
}
}
for (Class superClass = otherMethodDeclaringClass.getSuperclass(); superClass != null && superClass != Object.class; superClass = superClass.getSuperclass()) {
if (superClass == thisMethodDeclaringClass) {
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;
}
}
}
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;
}
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);
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) {
if (format == null) {
return ObjectReaderImplLocalDateTime.INSTANCE;
}
return new ObjectReaderImplLocalDateTime(format, locale);
}
if (fieldClass == LocalDate.class) {
if (format == null) {
return ObjectReaderImplLocalDate.INSTANCE;
}
return new ObjectReaderImplLocalDate(format, locale);
}
if (fieldClass == LocalTime.class) {
if (format == null) {
return ObjectReaderImplLocalTime.INSTANCE;
}
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;
}
}