ObjectReader.java
package com.alibaba.fastjson2.reader;
import com.alibaba.fastjson2.*;
import com.alibaba.fastjson2.util.Fnv;
import com.alibaba.fastjson2.util.TypeUtils;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
@SuppressWarnings({"rawtypes", "unchecked"})
public interface ObjectReader<T> {
long HASH_TYPE = Fnv.hashCode64("@type");
/**
* @return {@link T}
* @throws UnsupportedOperationException If the method is not overloaded or otherwise
*/
default T createInstance() {
return createInstance(0);
}
/**
* @return {@link T}
* @throws UnsupportedOperationException If the method is not overloaded or otherwise
*/
default T createInstance(long features) {
throw new UnsupportedOperationException();
}
/**
* @return {@link T}
* @throws UnsupportedOperationException If the method is not overloaded or otherwise
*/
default T createInstance(Collection collection) {
throw new UnsupportedOperationException(this.getClass().getName());
}
default void acceptExtra(Object object, String fieldName, Object fieldValue) {
}
default T createInstance(Map map, JSONReader.Feature... features) {
long featuresValue = 0;
for (JSONReader.Feature feature : features) {
featuresValue |= feature.mask;
}
return createInstance(map, featuresValue);
}
/**
* @return {@link T}
* @throws JSONException If a suitable ObjectReader is not found
*/
default T createInstance(Map map, long features) {
ObjectReaderProvider provider = JSONFactory.getDefaultObjectReaderProvider();
Object typeKey = map.get(getTypeKey());
if (typeKey instanceof String) {
String typeName = (String) typeKey;
long typeHash = Fnv.hashCode64(typeName);
ObjectReader<T> reader = null;
if ((features & JSONReader.Feature.SupportAutoType.mask) != 0 || this instanceof ObjectReaderSeeAlso) {
reader = autoType(provider, typeHash);
}
if (reader == null) {
reader = provider.getObjectReader(
typeName, getObjectClass(), features | getFeatures()
);
if (reader == null) {
throw new JSONException("No suitable ObjectReader found for" + typeName);
}
}
if (reader != this) {
return reader.createInstance(map, features);
}
}
T object = createInstance(0L);
for (Map.Entry entry : (Iterable<Map.Entry>) map.entrySet()) {
String entryKey = entry.getKey().toString();
Object fieldValue = entry.getValue();
FieldReader fieldReader = getFieldReader(entryKey);
if (fieldReader == null) {
acceptExtra(object, entryKey, entry.getValue());
continue;
}
Class fieldClass = fieldReader.fieldClass;
Type fieldType = fieldReader.fieldType;
boolean autoCast = true;
if (fieldValue != null) {
Class<?> valueClass = fieldValue.getClass();
if (!fieldReader.supportAcceptType(valueClass)) {
if (valueClass == String.class) {
if (fieldReader.fieldClass == java.util.Date.class) {
autoCast = false;
}
} else if (valueClass == Integer.class
&& (fieldReader.fieldClass == boolean.class || fieldReader.fieldClass == Boolean.class)
&& (features & JSONReader.Feature.NonZeroNumberCastToBooleanAsTrue.mask) != 0
) {
int intValue = ((Integer) fieldValue);
fieldValue = intValue != 0;
}
if (valueClass != fieldReader.fieldClass && autoCast) {
Function typeConvert = provider.getTypeConvert(valueClass, fieldReader.fieldClass);
if (typeConvert != null) {
fieldValue = typeConvert.apply(fieldValue);
}
}
}
}
Object typedFieldValue;
if (fieldValue == null || fieldType == fieldValue.getClass()) {
typedFieldValue = fieldValue;
} else {
if (fieldValue instanceof JSONObject) {
typedFieldValue = ((JSONObject) fieldValue).to(fieldType);
} else if (fieldValue instanceof JSONArray) {
typedFieldValue = ((JSONArray) fieldValue).to(fieldType);
} else if (features == 0 && !fieldClass.isInstance(fieldValue) && fieldReader.format == null) {
ObjectReader initReader = fieldReader.getInitReader();
if (initReader != null) {
String fieldValueJson = JSON.toJSONString(fieldValue);
typedFieldValue = initReader.readObject(JSONReader.of(fieldValueJson), null, null, 0L);
} else {
typedFieldValue = TypeUtils.cast(fieldValue, fieldClass, provider);
}
} else {
if (autoCast) {
String fieldValueJSONString = JSON.toJSONString(fieldValue);
try (JSONReader jsonReader = JSONReader.of(fieldValueJSONString)) {
ObjectReader fieldObjectReader = fieldReader.getObjectReader(jsonReader);
typedFieldValue = fieldObjectReader.readObject(jsonReader, null, entry.getKey(), features);
}
} else {
typedFieldValue = fieldValue;
}
}
}
fieldReader.accept(object, typedFieldValue);
}
Function buildFunction = getBuildFunction();
if (buildFunction != null) {
return (T) buildFunction.apply(object);
}
return object;
}
/**
* @throws UnsupportedOperationException If the method is not overloaded or otherwise
*/
default T createInstanceNoneDefaultConstructor(Map<Long, Object> values) {
throw new UnsupportedOperationException();
}
/**
* Features enabled by ObjectReader
*/
default long getFeatures() {
return 0L;
}
default String getTypeKey() {
return "@type";
}
default long getTypeKeyHash() {
return HASH_TYPE;
}
default Class<T> getObjectClass() {
return null;
}
default FieldReader getFieldReader(long hashCode) {
return null;
}
default FieldReader getFieldReaderLCase(long hashCode) {
return null;
}
default boolean setFieldValue(Object object, String fieldName, long fieldNameHashCode, int value) {
FieldReader fieldReader = getFieldReader(fieldNameHashCode);
if (fieldReader == null) {
return false;
}
fieldReader.accept(object, value);
return true;
}
default boolean setFieldValue(Object object, String fieldName, long fieldNameHashCode, long value) {
FieldReader fieldReader = getFieldReader(fieldNameHashCode);
if (fieldReader == null) {
return false;
}
fieldReader.accept(object, value);
return true;
}
default FieldReader getFieldReader(String fieldName) {
long fieldNameHash = Fnv.hashCode64(fieldName);
FieldReader fieldReader = getFieldReader(fieldNameHash);
if (fieldReader == null) {
long fieldNameHashLCase = Fnv.hashCode64LCase(fieldName);
if (fieldNameHashLCase != fieldNameHash) {
fieldReader = getFieldReaderLCase(fieldNameHashLCase);
}
}
return fieldReader;
}
default Function getBuildFunction() {
return null;
}
default ObjectReader autoType(JSONReader.Context context, long typeHash) {
return context.getObjectReaderAutoType(typeHash);
}
default ObjectReader autoType(ObjectReaderProvider provider, long typeHash) {
return provider.getObjectReader(typeHash);
}
/**
* @return {@link T}
* @throws JSONException If a suitable ObjectReader is not found
*/
default T readJSONBObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
if (jsonReader.isArray() &&
jsonReader.isSupportBeanArray()) {
return readArrayMappingJSONBObject(jsonReader, fieldType, fieldName, features);
}
T object = null;
jsonReader.nextIfObjectStart();
for (int i = 0; ; ++i) {
if (jsonReader.nextIfObjectEnd()) {
break;
}
long hash = jsonReader.readFieldNameHashCode();
if (hash == getTypeKeyHash() && i == 0) {
long typeHash = jsonReader.readTypeHashCode();
JSONReader.Context context = jsonReader.getContext();
ObjectReader reader = autoType(context, typeHash);
if (reader == null) {
String typeName = jsonReader.getString();
reader = context.getObjectReaderAutoType(typeName, null);
if (reader == null) {
throw new JSONException(jsonReader.info("No suitable ObjectReader found for" + typeName));
}
}
if (reader == this) {
continue;
}
return (T) reader.readJSONBObject(jsonReader, fieldType, fieldName, features);
}
if (hash == 0) {
continue;
}
FieldReader fieldReader = getFieldReader(hash);
if (fieldReader == null && jsonReader.isSupportSmartMatch(features | getFeatures())) {
long nameHashCodeLCase = jsonReader.getNameHashCodeLCase();
if (nameHashCodeLCase != hash) {
fieldReader = getFieldReaderLCase(nameHashCodeLCase);
}
}
if (fieldReader == null) {
jsonReader.skipValue();
continue;
}
if (object == null) {
object = createInstance(jsonReader.getContext().getFeatures() | features);
}
fieldReader.readFieldValue(jsonReader, object);
}
if (object == null) {
object = createInstance(jsonReader.getContext().getFeatures() | features);
}
return object;
}
/**
* @return {@link T}
* @throws UnsupportedOperationException If the method is not overloaded or otherwise
*/
default T readArrayMappingJSONBObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
throw new UnsupportedOperationException();
}
/**
* @return {@link T}
* @throws UnsupportedOperationException If the method is not overloaded or otherwise
*/
default T readArrayMappingObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
throw new UnsupportedOperationException();
}
/**
* @return {@link T}
*/
default T readObject(JSONReader jsonReader) {
return readObject(jsonReader, null, null, getFeatures());
}
default T readObject(JSONReader jsonReader, long features) {
return readObject(jsonReader, null, null, features);
}
/**
* @return {@link T}
* @throws JSONException If a suitable ObjectReader is not found
*/
T readObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features);
}