Skip to content

Commit

Permalink
speed up : toJavaObject
Browse files Browse the repository at this point in the history
  • Loading branch information
wenshao committed Jun 6, 2023
1 parent e036d13 commit 1a596e3
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 77 deletions.
Binary file modified .gitignore
Binary file not shown.
80 changes: 78 additions & 2 deletions core/src/main/java/com/alibaba/fastjson2/reader/FieldReader.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.alibaba.fastjson2.reader;

import com.alibaba.fastjson2.JSONPath;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.*;
import com.alibaba.fastjson2.annotation.JSONField;
import com.alibaba.fastjson2.codec.FieldInfo;
import com.alibaba.fastjson2.schema.JSONSchema;
Expand All @@ -11,6 +10,7 @@
import java.lang.reflect.*;
import java.time.*;
import java.util.*;
import java.util.function.Function;

public abstract class FieldReader<T>
implements Comparable<FieldReader> {
Expand Down Expand Up @@ -122,6 +122,15 @@ public ObjectReader getObjectReader(JSONReader.Context context) {
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;
}
Expand Down Expand Up @@ -370,6 +379,73 @@ public void accept(T object, double 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 == java.util.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), null, null, features);
} else {
typedFieldValue = TypeUtils.cast(fieldValue, fieldClass, provider);
}
} else {
if (autoCast) {
String fieldValueJSONString = JSON.toJSONString(fieldValue);
JSONReader.Context readContext = JSONFactory.createReadContext();
if ((features & JSONReader.Feature.SupportSmartMatch.mask) != 0) {
readContext.config(JSONReader.Feature.SupportSmartMatch);
}
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

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;
Expand Down Expand Up @@ -86,68 +85,7 @@ typeName, getObjectClass(), features | getFeatures()
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);
JSONReader.Context readContext = JSONFactory.createReadContext();
if ((features & JSONReader.Feature.SupportSmartMatch.mask) != 0) {
readContext.config(JSONReader.Feature.SupportSmartMatch);
}
try (JSONReader jsonReader = JSONReader.of(fieldValueJSONString, readContext)) {
ObjectReader fieldObjectReader = fieldReader.getObjectReader(jsonReader);
typedFieldValue = fieldObjectReader.readObject(jsonReader, null, entry.getKey(), features);
}
} else {
typedFieldValue = fieldValue;
}
}
}
fieldReader.accept(object, typedFieldValue);
fieldReader.acceptAny(object, fieldValue, features);
}

Function buildFunction = getBuildFunction();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.alibaba.fastjson2.reader;

import com.alibaba.fastjson2.JSONB;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.*;
import com.alibaba.fastjson2.schema.JSONSchema;
import com.alibaba.fastjson2.util.BeanUtils;
import com.alibaba.fastjson2.util.Fnv;
Expand Down Expand Up @@ -543,4 +541,91 @@ protected void initStringFieldAsEmpty(Object object) {
}
}
}

public T createInstance(Map map, long features) {
ObjectReaderProvider provider = JSONFactory.getDefaultObjectReaderProvider();
Object typeKey = map.get(this.typeKey);

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 != this && reader != null) {
return reader.createInstance(map, features);
}
}

T object = createInstance(0L);

if (extraFieldReader == null
&& ((features | this.features) & JSONReader.Feature.SupportSmartMatch.mask) == 0
) {
for (FieldReader fieldReader : fieldReaders) {
Object fieldValue = map.get(fieldReader.fieldName);
if (fieldValue == null) {
continue;
}

if (fieldValue.getClass() == fieldReader.fieldType) {
fieldReader.accept(object, fieldValue);
} else {
if ((fieldReader instanceof FieldReaderList)
&& fieldValue instanceof JSONArray
) {
ObjectReader objectReader = fieldReader.getObjectReader(provider);
Object fieldValueList = objectReader.createInstance((JSONArray) fieldValue);
fieldReader.accept(object, fieldValueList);
continue;
} else if (fieldValue instanceof JSONObject
&& fieldReader.fieldType != JSONObject.class
) {
JSONObject jsonObject = (JSONObject) fieldValue;
boolean fieldBased = ((this.features | features) & JSONReader.Feature.FieldBased.mask) != 0;
ObjectReader<T> objectReader = provider.getObjectReader(fieldReader.fieldType, fieldBased);
Object fieldValueJavaBean = objectReader.createInstance(jsonObject, features);
fieldReader.accept(object, fieldValueJavaBean);
continue;
}

fieldReader.acceptAny(object, fieldValue, features);
}
}
} else {
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;
}

if (fieldValue != null
&& fieldValue.getClass() == fieldReader.fieldType
) {
fieldReader.accept(object, fieldValue);
} else {
fieldReader.acceptAny(object, fieldValue, features);
}
}
}

Function buildFunction = getBuildFunction();
if (buildFunction != null) {
return (T) buildFunction.apply(object);
}

return object;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.function.Function;

import static com.alibaba.fastjson2.util.JDKUtils.JVM_VERSION;
import static com.alibaba.fastjson2.util.TypeUtils.CLASS_JSON_OBJECT_1x;

public final class ObjectReaderImplList
implements ObjectReader {
Expand Down Expand Up @@ -220,7 +221,13 @@ public Object createInstance(Collection collection) {

ObjectReaderProvider provider = JSONFactory.getDefaultObjectReaderProvider();

Collection list = (Collection) createInstance(0L);
Collection list;
if (instanceType == ArrayList.class) {
list = new ArrayList(collection.size());
} else {
list = (Collection) createInstance(0L);
}

for (Object item : collection) {
if (item == null) {
list.add(null);
Expand All @@ -229,7 +236,12 @@ public Object createInstance(Collection collection) {

Object value = item;
Class<?> valueClass = value.getClass();
if (valueClass != itemType) {
if ((valueClass == JSONObject.class || valueClass == CLASS_JSON_OBJECT_1x) && this.itemClass != valueClass) {
if (itemObjectReader == null) {
itemObjectReader = provider.getObjectReader(itemType);
}
value = itemObjectReader.createInstance((JSONObject) value, 0L);
} else if (valueClass != itemType) {
Function typeConvert = provider.getTypeConvert(valueClass, itemType);
if (typeConvert != null) {
value = typeConvert.apply(value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import static com.alibaba.fastjson2.JSONB.Constants.*;
import static com.alibaba.fastjson2.util.JDKUtils.UNSAFE_SUPPORT;
import static com.alibaba.fastjson2.util.TypeUtils.CLASS_JSON_OBJECT_1x;

public final class ObjectReaderImplMap
implements ObjectReader {
Expand Down Expand Up @@ -138,7 +139,7 @@ public static ObjectReader of(Type fieldType, Class mapType, long features) {
break;
default:
if (instanceType == JSONObject1O.class) {
Class objectClass = TypeUtils.loadClass("com.alibaba.fastjson.JSONObject");
Class objectClass = CLASS_JSON_OBJECT_1x;
builder = createObjectSupplier(objectClass);
instanceType = LinkedHashMap.class;
} else if (mapType == CLASS_UNMODIFIABLE_MAP) {
Expand Down
Loading

0 comments on commit 1a596e3

Please sign in to comment.