Skip to content

Commit

Permalink
improved jsonpath performance
Browse files Browse the repository at this point in the history
  • Loading branch information
wenshao committed Jul 27, 2023
1 parent 2bd4b7e commit e738baf
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 197 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ public static void extract() throws Exception {
long millis = System.currentTimeMillis() - start;
System.out.println("JSONPathMultiBenchmark2-extract millis : " + millis);
}
/// zulu8.62.0.19 : 792
/// zulu8.62.0.19 : 792 541
}

public static void main(String[] args) throws Exception {
// eval();
evalMulti();
// evalMulti();
extract();
}
}
124 changes: 42 additions & 82 deletions core/src/main/java/com/alibaba/fastjson2/JSONPathTypedMultiNames.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
package com.alibaba.fastjson2;

import com.alibaba.fastjson2.reader.FieldReader;
import com.alibaba.fastjson2.reader.ObjectReaderCreator;
import com.alibaba.fastjson2.reader.ObjectReaderAdapter;
import com.alibaba.fastjson2.util.TypeUtils;
import com.alibaba.fastjson2.writer.FieldWriter;
import com.alibaba.fastjson2.writer.ObjectWriter;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Map;

class JSONPathTypedMultiNames
extends JSONPathTypedMulti {
final JSONPath prefix;
final JSONPath[] namePaths;
final String[] names;
final long[] hashCodes;
final short[] mapping;
final FieldReader[] fieldReaders;
final ObjectReaderAdapter<Object[]> objectReader;

JSONPathTypedMultiNames(
JSONPath[] paths,
Expand All @@ -35,50 +33,52 @@ class JSONPathTypedMultiNames
this.prefix = prefix;
this.namePaths = namePaths;
this.names = new String[paths.length];

long[] hashCodes = new long[paths.length];
fieldReaders = new FieldReader[paths.length];
for (int i = 0; i < paths.length; i++) {
JSONPathSingleName jsonPathSingleName = (JSONPathSingleName) namePaths[i];
String fieldName = jsonPathSingleName.name;
names[i] = fieldName;
hashCodes[i] = jsonPathSingleName.nameHashCode;
String format = formats != null ? formats[i] : null;

Type fieldType = types[i];
Class fieldClass = TypeUtils.getClass(fieldType);

long fieldFeatures = 0;
if (ignoreError(i)) {
fieldFeatures |= JSONReader.Feature.NullOnError.mask;
}
long[] fieldReaderFeatures = new long[names.length];
if (pathFeatures != null) {
for (int i = 0; i < pathFeatures.length; i++) {
if ((pathFeatures[i] & Feature.NullOnError.mask) != 0) {
fieldReaderFeatures[i] |= JSONReader.Feature.NullOnError.mask;
}
}
fieldReaders[i] = ObjectReaderCreator.INSTANCE.createFieldReader(
null,
null,
fieldName,
fieldType,
fieldClass,
i,
fieldFeatures,
format,
null,
null,
null,
null,
null,
null
);
}

this.hashCodes = Arrays.copyOf(hashCodes, hashCodes.length);
Arrays.sort(this.hashCodes);

mapping = new short[this.hashCodes.length];
for (int i = 0; i < hashCodes.length; i++) {
long hashCode = hashCodes[i];
int index = Arrays.binarySearch(this.hashCodes, hashCode);
mapping[index] = (short) i;
Type[] fieldTypes = types.clone();
for (int i = 0; i < fieldTypes.length; i++) {
Type fieldType = fieldTypes[i];
if (fieldType == boolean.class) {
fieldTypes[i] = Boolean.class;
} else if (fieldType == char.class) {
fieldTypes[i] = Character.class;
} else if (fieldType == byte.class) {
fieldTypes[i] = Byte.class;
} else if (fieldType == short.class) {
fieldTypes[i] = Short.class;
} else if (fieldType == int.class) {
fieldTypes[i] = Integer.class;
} else if (fieldType == long.class) {
fieldTypes[i] = Long.class;
} else if (fieldType == float.class) {
fieldTypes[i] = Float.class;
} else if (fieldType == double.class) {
fieldTypes[i] = Double.class;
}
}

final int length = names.length;
objectReader = (ObjectReaderAdapter<Object[]>) JSONFactory.getDefaultObjectReaderProvider()
.createObjectReader(
names,
fieldTypes,
fieldReaderFeatures,
() -> new Object[length],
(o, i, v) -> o[i] = v
);
this.fieldReaders = objectReader.getFieldReaders();
}

@Override
Expand All @@ -100,23 +100,7 @@ public Object eval(Object root) {
}

if (object instanceof Map) {
Map map = (Map) object;
for (int i = 0; i < names.length; i++) {
Object result = map.get(names[i]);
Type type = types[i];
if (result != null && result.getClass() != type) {
if (type == Long.class) {
result = TypeUtils.toLong(result);
} else if (type == BigDecimal.class) {
result = TypeUtils.toBigDecimal(result);
// } else if (type == String[].class) {
// result = TypeUtils.toStringArray(result);
} else {
result = TypeUtils.cast(result, type);
}
}
array[i] = result;
}
return objectReader.createInstance((Map) object, 0);
} else {
ObjectWriter objectReader = JSONFactory.defaultObjectWriterProvider
.getObjectWriter(
Expand Down Expand Up @@ -165,30 +149,6 @@ public Object extract(JSONReader jsonReader) {
throw new JSONException(jsonReader.info("illegal input, expect '[', but " + jsonReader.current()));
}

Object[] values = new Object[paths.length];
while (!jsonReader.nextIfObjectEnd()) {
long nameHashCode = jsonReader.readFieldNameHashCode();

int m = Arrays.binarySearch(hashCodes, nameHashCode);
if (m < 0) {
jsonReader.skipValue();
continue;
}

int index = this.mapping[m];
FieldReader fieldReader = fieldReaders[index];
Object fieldValue;
try {
fieldValue = fieldReader.readFieldValue(jsonReader);
} catch (Exception e) {
if (!ignoreError(index)) {
throw e;
}
fieldValue = null;
}
values[index] = fieldValue;
}

return values;
return objectReader.readObject(jsonReader, null, null, 0);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.alibaba.fastjson2;

import com.alibaba.fastjson2.reader.FieldReader;

import java.lang.reflect.Type;
import java.time.ZoneId;
import java.util.Arrays;

public class JSONPathTypedMultiNamesPrefixIndex1
extends JSONPathTypedMultiNames {
Expand Down Expand Up @@ -53,34 +50,6 @@ public Object extract(JSONReader jsonReader) {
return new Object[paths.length];
}

if (!jsonReader.nextIfObjectStart()) {
throw new JSONException(jsonReader.info("illegal input, expect '[', but " + jsonReader.current()));
}

Object[] values = new Object[paths.length];
while (!jsonReader.nextIfObjectEnd()) {
long nameHashCode = jsonReader.readFieldNameHashCode();

int m = Arrays.binarySearch(hashCodes, nameHashCode);
if (m < 0) {
jsonReader.skipValue();
continue;
}

int index = this.mapping[m];
FieldReader fieldReader = fieldReaders[index];
Object fieldValue;
try {
fieldValue = fieldReader.readFieldValue(jsonReader);
} catch (Exception e) {
if (!ignoreError(index)) {
throw e;
}
fieldValue = null;
}
values[index] = fieldValue;
}

return values;
return objectReader.readObject(jsonReader);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.alibaba.fastjson2;

import com.alibaba.fastjson2.reader.FieldReader;

import java.lang.reflect.Type;
import java.time.ZoneId;
import java.util.Arrays;

public class JSONPathTypedMultiNamesPrefixName1
extends JSONPathTypedMultiNames {
Expand Down Expand Up @@ -62,30 +59,6 @@ public Object extract(JSONReader jsonReader) {
throw new JSONException(jsonReader.info("illegal input, expect '[', but " + jsonReader.current()));
}

Object[] values = new Object[paths.length];
while (!jsonReader.nextIfObjectEnd()) {
long nameHashCode = jsonReader.readFieldNameHashCode();

int m = Arrays.binarySearch(hashCodes, nameHashCode);
if (m < 0) {
jsonReader.skipValue();
continue;
}

int index = this.mapping[m];
FieldReader fieldReader = fieldReaders[index];
Object fieldValue;
try {
fieldValue = fieldReader.readFieldValue(jsonReader);
} catch (Exception e) {
if (!ignoreError(index)) {
throw e;
}
fieldValue = null;
}
values[index] = fieldValue;
}

return values;
return objectReader.readObject(jsonReader);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import java.lang.reflect.Type;
import java.time.ZoneId;
import java.util.Arrays;

public class JSONPathTypedMultiNamesPrefixName2
extends JSONPathTypedMultiNames {
Expand Down Expand Up @@ -89,40 +88,7 @@ public Object extract(JSONReader jsonReader) {
return new Object[paths.length];
}

if (!jsonReader.nextIfObjectStart()) {
throw error(jsonReader);
}

Object[] values = new Object[paths.length];
while (!jsonReader.nextIfObjectEnd()) {
if (jsonReader.isEnd()) {
throw error(jsonReader);
}

int m = Arrays.binarySearch(
hashCodes,
jsonReader.readFieldNameHashCode()
);

if (m < 0) {
jsonReader.skipValue();
continue;
}

int index = this.mapping[m];
Object fieldValue;
try {
fieldValue = fieldReaders[index].readFieldValue(jsonReader);
} catch (Exception e) {
if (!ignoreError(index)) {
throw e;
}
fieldValue = null;
}
values[index] = fieldValue;
}

return values;
return objectReader.readObject(jsonReader);
}

private static JSONException error(JSONReader jsonReader) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,15 @@ protected void acceptNull(T object) {

@Override
public void readFieldValue(JSONReader jsonReader, T object) {
Date date = (Date) dateReader.readObject(jsonReader, fieldType, fieldName, features);
Date date;
try {
date = (Date) dateReader.readObject(jsonReader, fieldType, fieldName, features);
} catch (Exception e) {
if ((features & JSONReader.Feature.NullOnError.mask) == 0) {
throw e;
}
date = null;
}
accept(object, date);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ public void readFieldValue(JSONReader jsonReader, T object) {
return;
}

Object value;
try {
Object value;
if (jsonReader.nextIfNull()) {
if (fieldClass == OptionalInt.class) {
value = OptionalInt.empty();
Expand All @@ -151,22 +151,26 @@ public void readFieldValue(JSONReader jsonReader, T object) {
} else {
value = objectReader.readObject(jsonReader, fieldType, fieldName, features);
}
accept(object, value);

if (noneStaticMemberClass) {
BeanUtils.setNoneStaticMemberClassParent(value, object);
}
} catch (JSONSchemaValidException ex) {
throw ex;
} catch (Exception | IllegalAccessError ex) {
Member member = this.field != null ? this.field : this.method;
String message;
if (member != null) {
message = "read field '" + member.getDeclaringClass().getName() + "." + member.getName();
} else {
message = "read field " + fieldName + " error";
if ((features & JSONReader.Feature.NullOnError.mask) == 0) {
Member member = this.field != null ? this.field : this.method;
String message;
if (member != null) {
message = "read field '" + member.getDeclaringClass().getName() + "." + member.getName();
} else {
message = "read field " + fieldName + " error";
}
throw new JSONException(jsonReader.info(message), ex);
}
throw new JSONException(jsonReader.info(message), ex);
value = null;
}

accept(object, value);

if (noneStaticMemberClass) {
BeanUtils.setNoneStaticMemberClassParent(value, object);
}
}

Expand Down
Loading

0 comments on commit e738baf

Please sign in to comment.