Skip to content

Commit fffeca3

Browse files
committed
reflection support array
1 parent d6f1cd9 commit fffeca3

14 files changed

Lines changed: 471 additions & 354 deletions

demo/src/test/java/com/jsoniter/demo/ConstructorBinding.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
99
import com.jsoniter.DecodingMode;
1010
import com.jsoniter.JsonIterator;
11-
import com.jsoniter.ReflectionDecoder;
11+
import com.jsoniter.ReflectionObjectDecoder;
1212
import com.jsoniter.annotation.JacksonAnnotationSupport;
1313
import com.jsoniter.spi.ExtensionManager;
1414
import com.jsoniter.spi.TypeLiteral;
@@ -72,15 +72,15 @@ public void benchSetup(BenchmarkParams params) {
7272
JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_STRICTLY);
7373
}
7474
if (params.getBenchmark().contains("withJsoniterReflection")) {
75-
ExtensionManager.registerTypeDecoder(TestObject.class, new ReflectionDecoder(TestObject.class));
75+
ExtensionManager.registerTypeDecoder(TestObject.class, new ReflectionObjectDecoder(TestObject.class));
7676
}
7777
}
7878
}
7979

8080
@Test
8181
public void test() throws IOException {
8282
benchSetup(null);
83-
ExtensionManager.registerTypeDecoder(TestObject.class, new ReflectionDecoder(TestObject.class));
83+
ExtensionManager.registerTypeDecoder(TestObject.class, new ReflectionObjectDecoder(TestObject.class));
8484
System.out.println(withJsoniter());
8585
System.out.println(withJackson());
8686
}

demo/src/test/java/com/jsoniter/demo/PrivateFieldBinding.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.fasterxml.jackson.databind.ObjectMapper;
66
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
77
import com.jsoniter.JsonIterator;
8-
import com.jsoniter.ReflectionDecoder;
8+
import com.jsoniter.ReflectionObjectDecoder;
99
import com.jsoniter.annotation.JacksonAnnotationSupport;
1010
import com.jsoniter.spi.ExtensionManager;
1111
import com.jsoniter.spi.TypeLiteral;
@@ -53,7 +53,7 @@ public void benchSetup() {
5353
typeRef = new TypeReference<TestObject>() {
5454
};
5555
JacksonAnnotationSupport.enable();
56-
ExtensionManager.registerTypeDecoder(TestObject.class, new ReflectionDecoder(TestObject.class));
56+
ExtensionManager.registerTypeDecoder(TestObject.class, new ReflectionObjectDecoder(TestObject.class));
5757
jackson = new ObjectMapper();
5858
jackson.registerModule(new AfterburnerModule());
5959
}

demo/src/test/java/com/jsoniter/demo/SetterBinding.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
66
import com.jsoniter.DecodingMode;
77
import com.jsoniter.JsonIterator;
8-
import com.jsoniter.ReflectionDecoder;
8+
import com.jsoniter.ReflectionObjectDecoder;
99
import com.jsoniter.annotation.JacksonAnnotationSupport;
1010
import com.jsoniter.spi.ExtensionManager;
1111
import com.jsoniter.spi.TypeLiteral;
@@ -67,15 +67,15 @@ public void benchSetup(BenchmarkParams params) {
6767
JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_STRICTLY);
6868
}
6969
if (params.getBenchmark().contains("withJsoniterReflection")) {
70-
ExtensionManager.registerTypeDecoder(ConstructorBinding.TestObject.class, new ReflectionDecoder(ConstructorBinding.TestObject.class));
70+
ExtensionManager.registerTypeDecoder(ConstructorBinding.TestObject.class, new ReflectionObjectDecoder(ConstructorBinding.TestObject.class));
7171
}
7272
}
7373
}
7474

7575
@Test
7676
public void test() throws IOException {
7777
benchSetup(null);
78-
ExtensionManager.registerTypeDecoder(ConstructorBinding.TestObject.class, new ReflectionDecoder(ConstructorBinding.TestObject.class));
78+
ExtensionManager.registerTypeDecoder(ConstructorBinding.TestObject.class, new ReflectionObjectDecoder(ConstructorBinding.TestObject.class));
7979
System.out.println(withJsoniter());
8080
System.out.println(withJackson());
8181
}

demo/src/test/java/com/jsoniter/demo/SimpleObjectBinding.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
99
import com.jsoniter.DecodingMode;
1010
import com.jsoniter.JsonIterator;
11-
import com.jsoniter.ReflectionDecoder;
11+
import com.jsoniter.ReflectionObjectDecoder;
1212
import com.jsoniter.spi.ExtensionManager;
1313
import com.jsoniter.spi.TypeLiteral;
1414
import org.junit.Test;
@@ -63,7 +63,7 @@ public void benchSetup(BenchmarkParams params) {
6363
testObject = new TestObject();
6464
if (params != null) {
6565
if (params.getBenchmark().contains("withReflection")) {
66-
ExtensionManager.registerTypeDecoder(TestObject.class, new ReflectionDecoder(TestObject.class));
66+
ExtensionManager.registerTypeDecoder(TestObject.class, new ReflectionObjectDecoder(TestObject.class));
6767
}
6868
if (params.getBenchmark().contains("withBindApiStrictMode")) {
6969
JsonIterator.setMode(DecodingMode.STATIC_MODE);
@@ -77,7 +77,7 @@ public void benchSetup(BenchmarkParams params) {
7777
@Test
7878
public void test() throws IOException {
7979
benchSetup(null);
80-
ExtensionManager.registerTypeDecoder(TestObject.class, new ReflectionDecoder(TestObject.class));
80+
ExtensionManager.registerTypeDecoder(TestObject.class, new ReflectionObjectDecoder(TestObject.class));
8181
System.out.println(withIterator());
8282
System.out.println(withIteratorIfElse());
8383
System.out.println(withIteratorIntern());

src/main/java/com/jsoniter/Codegen.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ private synchronized static Decoder gen(String cacheKey, Type type) {
4040
}
4141
}
4242
if (mode == DecodingMode.REFLECTION_MODE) {
43-
return new ReflectionDecoder((Class) type);
43+
return ReflectionDecoder.create(type);
4444
}
4545
try {
4646
return (Decoder) Class.forName(cacheKey).newInstance();
@@ -147,24 +147,32 @@ private static String genSource(String cacheKey, Class clazz, Type[] typeArgs) {
147147
return CodegenImplArray.genCollection(clazz, typeArgs);
148148
}
149149
ClassDescriptor desc = ExtensionManager.getClassDescriptor(clazz, false);
150+
if (shouldUseStrictMode(desc)) {
151+
return CodegenImplObject.genObjectUsingStrict(clazz, cacheKey, desc);
152+
} else {
153+
return CodegenImplObject.genObjectUsingHash(clazz, cacheKey, desc);
154+
}
155+
}
156+
157+
private static boolean shouldUseStrictMode(ClassDescriptor desc) {
158+
if (mode == DecodingMode.STATIC_MODE) {
159+
return true;
160+
}
150161
List<Binding> allBindings = desc.allDecoderBindings();
151162
for (Binding binding : allBindings) {
152163
if (binding.failOnMissing || binding.failOnPresent || binding.skip) {
153164
// only slice support mandatory tracking
154-
return CodegenImplObject.genObjectUsingSlice(clazz, cacheKey, desc);
165+
return true;
155166
}
156167
}
157168
if (desc.failOnUnknownFields) {
158169
// only slice support unknown field tracking
159-
return CodegenImplObject.genObjectUsingSlice(clazz, cacheKey, desc);
170+
return true;
160171
}
161172
if (allBindings.isEmpty()) {
162-
return CodegenImplObject.genObjectUsingSkip(clazz, desc.ctor);
163-
}
164-
if (mode == DecodingMode.STATIC_MODE) {
165-
return CodegenImplObject.genObjectUsingSlice(clazz, cacheKey, desc);
173+
return true;
166174
}
167-
return CodegenImplObject.genObjectUsingHash(clazz, cacheKey, desc);
175+
return false;
168176
}
169177

170178
public static void staticGenDecoders(TypeLiteral[] typeLiterals) {

src/main/java/com/jsoniter/CodegenImplObject.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class CodegenImplObject {
1919
}};
2020

2121

22-
public static String genObjectUsingSlice(Class clazz, String cacheKey, ClassDescriptor desc) {
22+
public static String genObjectUsingStrict(Class clazz, String cacheKey, ClassDescriptor desc) {
2323
// TODO: when setter is single argument, decode like field
2424
List<Binding> allBindings = desc.allDecoderBindings();
2525
int requiredIdx = 0;
@@ -268,11 +268,11 @@ public static String genObjectUsingHash(Class clazz, String cacheKey, ClassDescr
268268
int intHash = (int) hash;
269269
if (intHash == 0) {
270270
// hash collision, 0 can not be used as sentinel
271-
return genObjectUsingSlice(clazz, cacheKey, desc);
271+
return genObjectUsingStrict(clazz, cacheKey, desc);
272272
}
273273
if (knownHashes.contains(intHash)) {
274274
// hash collision with other field can not be used as sentinel
275-
return genObjectUsingSlice(clazz, cacheKey, desc);
275+
return genObjectUsingStrict(clazz, cacheKey, desc);
276276
}
277277
knownHashes.add(intHash);
278278
append(lines, "case " + intHash + ": ");
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.jsoniter;
2+
3+
import com.jsoniter.spi.Decoder;
4+
import com.jsoniter.spi.TypeLiteral;
5+
6+
import java.io.IOException;
7+
import java.lang.reflect.Array;
8+
9+
public class ReflectionArrayDecoder implements Decoder {
10+
11+
private final Class componentType;
12+
private final TypeLiteral componentTypeLiteral;
13+
14+
public ReflectionArrayDecoder(Class clazz) {
15+
componentType = clazz.getComponentType();
16+
componentTypeLiteral = TypeLiteral.create(componentType);
17+
}
18+
19+
@Override
20+
public Object decode(JsonIterator iter) throws IOException {
21+
if (iter.readNull()) {
22+
return null;
23+
}
24+
if (!CodegenAccess.readArrayStart(iter)) {
25+
return Array.newInstance(componentType, 0);
26+
}
27+
Object a1 = CodegenAccess.read(iter, componentTypeLiteral);
28+
if (CodegenAccess.nextToken(iter) != ',') {
29+
Object arr = Array.newInstance(componentType, 1);
30+
Array.set(arr, 0, a1);
31+
return arr;
32+
}
33+
Object a2 = CodegenAccess.read(iter, componentTypeLiteral);
34+
if (CodegenAccess.nextToken(iter) != ',') {
35+
Object arr = Array.newInstance(componentType, 2);
36+
Array.set(arr, 0, a1);
37+
Array.set(arr, 1, a2);
38+
return arr;
39+
}
40+
Object a3 = CodegenAccess.read(iter, componentTypeLiteral);
41+
if (CodegenAccess.nextToken(iter) != ',') {
42+
Object arr = Array.newInstance(componentType, 3);
43+
Array.set(arr, 0, a1);
44+
Array.set(arr, 1, a2);
45+
Array.set(arr, 2, a3);
46+
return arr;
47+
}
48+
Object a4 = CodegenAccess.read(iter, componentTypeLiteral);
49+
Object arr = Array.newInstance(componentType, 8);
50+
Array.set(arr, 0, a1);
51+
Array.set(arr, 1, a2);
52+
Array.set(arr, 2, a3);
53+
Array.set(arr, 3, a4);
54+
int i = 4;
55+
int arrLen = 8;
56+
while (CodegenAccess.nextToken(iter) == ',') {
57+
if (i == arrLen) {
58+
Object newArr = Array.newInstance(componentType, 2 * arrLen);
59+
System.arraycopy(arr, 0, newArr, 0, arrLen);
60+
arr = newArr;
61+
arrLen = 2 * arrLen;
62+
}
63+
Array.set(arr, i++, CodegenAccess.read(iter, componentTypeLiteral));
64+
}
65+
if (i == arrLen) {
66+
return arr;
67+
}
68+
Object newArr = Array.newInstance(componentType, i);
69+
System.arraycopy(arr, 0, newArr, 0, i);
70+
return newArr;
71+
}
72+
}

0 commit comments

Comments
 (0)