Skip to content

Commit ba8d566

Browse files
committed
add reflection decoder
1 parent bfd25b0 commit ba8d566

12 files changed

Lines changed: 298 additions & 50 deletions

src/main/java/com/jsoniter/Binding.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
package com.jsoniter;
22

33
import java.lang.annotation.Annotation;
4+
import java.lang.reflect.Field;
45
import java.lang.reflect.Type;
56

67
public class Binding {
78
// input
89
public Class clazz;
910
public String name;
1011
public Type valueType;
12+
public TypeLiteral valueTypeLiteral;
1113
public Annotation[] annotations;
1214
// output
1315
public String[] fromNames;
1416
public Decoder decoder;
17+
// optional
18+
public Field field;
19+
public int idx;
1520

1621
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
1722
if (annotations == null) {
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.jsoniter;
22

3+
import java.lang.reflect.Constructor;
34
import java.util.ArrayList;
45
import java.util.List;
56

@@ -9,11 +10,11 @@ public class CustomizedConstructor {
910
* otherwise use static method
1011
*/
1112
public String staticMethodName;
13+
// optional
14+
public Constructor ctor;
1215

1316
/**
1417
* the parameters to call constructor or static method
1518
*/
1619
public List<Binding> parameters = new ArrayList<Binding>();
17-
18-
public static CustomizedConstructor DEFAULT_INSTANCE = new CustomizedConstructor();
1920
}

src/main/java/com/jsoniter/ExtensionManager.java

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.lang.reflect.Modifier;
66
import java.lang.reflect.Type;
77
import java.util.ArrayList;
8+
import java.util.Arrays;
89
import java.util.List;
910

1011
public class ExtensionManager {
@@ -16,40 +17,79 @@ public static void registerExtension(Extension extension) {
1617
}
1718

1819
public static CustomizedConstructor getCtor(Class clazz) {
20+
return getCtor(clazz, false);
21+
}
22+
23+
public static CustomizedConstructor getCtor(Class clazz, boolean includingPrivate) {
1924
for (Extension extension : extensions) {
2025
CustomizedConstructor ctor = extension.getConstructor(clazz);
2126
if (ctor != null) {
27+
if (ctor.ctor != null && includingPrivate) {
28+
ctor.ctor.setAccessible(true);
29+
}
2230
for (Binding param : ctor.parameters) {
2331
if (param.fromNames == null) {
2432
param.fromNames = new String[]{param.name};
2533
}
2634
param.clazz = clazz;
35+
param.valueTypeLiteral = createTypeLiteral(param.valueType);
2736
updateFromNames(param);
2837
}
2938
return ctor;
3039
}
3140
}
32-
return CustomizedConstructor.DEFAULT_INSTANCE;
41+
CustomizedConstructor cctor = new CustomizedConstructor();
42+
try {
43+
cctor.ctor = clazz.getDeclaredConstructor();
44+
if (includingPrivate) {
45+
cctor.ctor.setAccessible(true);
46+
}
47+
} catch (Exception e) {
48+
throw new RuntimeException(e);
49+
}
50+
return cctor;
3351
}
3452

3553
public static List<Binding> getFields(Class clazz) {
54+
return getFields(clazz, false);
55+
}
56+
57+
public static List<Binding> getFields(Class clazz, boolean includingPrivate) {
3658
ArrayList<Binding> bindings = new ArrayList<Binding>();
37-
for (Field field : clazz.getFields()) {
59+
List<Field> allFields = Arrays.asList(clazz.getFields());
60+
if (includingPrivate) {
61+
allFields = new ArrayList<Field>();
62+
Class current = clazz;
63+
while (current != null) {
64+
allFields.addAll(Arrays.asList(current.getDeclaredFields()));
65+
current = current.getSuperclass();
66+
}
67+
}
68+
for (Field field : allFields) {
3869
if (Modifier.isStatic(field.getModifiers())) {
3970
continue;
4071
}
72+
if (includingPrivate) {
73+
field.setAccessible(true);
74+
}
4175
Binding binding = new Binding();
4276
binding.fromNames = new String[]{field.getName()};
4377
binding.name = field.getName();
4478
binding.valueType = field.getType();
79+
binding.valueTypeLiteral = createTypeLiteral(binding.valueType);
4580
binding.clazz = clazz;
4681
binding.annotations = field.getAnnotations();
82+
binding.field = field;
4783
updateFromNames(binding);
4884
bindings.add(binding);
4985
}
5086
return bindings;
5187
}
5288

89+
private static TypeLiteral createTypeLiteral(Type valueType) {
90+
return new TypeLiteral(valueType, TypeLiteral.generateDecoderCacheKey(valueType));
91+
}
92+
5393
private static void updateFromNames(Binding binding) {
5494
for (Extension extension : extensions) {
5595
if (extension.updateBinding(binding)) {
@@ -59,6 +99,10 @@ private static void updateFromNames(Binding binding) {
5999
}
60100

61101
public static List<CustomizedSetter> getSetters(Class clazz) {
102+
return getSetters(clazz, false);
103+
}
104+
105+
public static List<CustomizedSetter> getSetters(Class clazz, boolean includingPrivate) {
62106
ArrayList<CustomizedSetter> setters = new ArrayList<CustomizedSetter>();
63107
for (Method method : clazz.getMethods()) {
64108
if (Modifier.isStatic(method.getModifiers())) {
@@ -109,6 +153,10 @@ public static List<CustomizedSetter> getSetters(Class clazz) {
109153
}
110154

111155
public static List<Binding> getGetters(Class clazz) {
156+
return getGetters(clazz, false);
157+
}
158+
159+
public static List<Binding> getGetters(Class clazz, boolean includingPrivate) {
112160
ArrayList<Binding> getters = new ArrayList<Binding>();
113161
for (Method method : clazz.getMethods()) {
114162
if (Modifier.isStatic(method.getModifiers())) {
@@ -140,4 +188,20 @@ public static List<Binding> getGetters(Class clazz) {
140188
}
141189
return getters;
142190
}
191+
192+
public static void registerTypeDecoder(Class clazz, Decoder decoder) {
193+
Codegen.addNewDecoder(TypeLiteral.generateDecoderCacheKey(clazz), decoder);
194+
}
195+
196+
public static void registerTypeDecoder(TypeLiteral typeLiteral, Decoder decoder) {
197+
Codegen.addNewDecoder(typeLiteral.cacheKey, decoder);
198+
}
199+
200+
public static void registerFieldDecoder(Class clazz, String field, Decoder decoder) {
201+
Codegen.addNewDecoder(field + "@" + TypeLiteral.generateDecoderCacheKey(clazz), decoder);
202+
}
203+
204+
public static void registerFieldDecoder(TypeLiteral typeLiteral, String field, Decoder decoder) {
205+
Codegen.addNewDecoder(field + "@" + typeLiteral.cacheKey, decoder);
206+
}
143207
}

src/main/java/com/jsoniter/JsonIterator.java

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -344,26 +344,6 @@ public void skip() throws IOException {
344344
IterImplSkip.skip(this);
345345
}
346346

347-
public static void registerTypeDecoder(Class clazz, Decoder decoder) {
348-
Codegen.addNewDecoder(TypeLiteral.generateDecoderCacheKey(clazz), decoder);
349-
}
350-
351-
public static void registerTypeDecoder(TypeLiteral typeLiteral, Decoder decoder) {
352-
Codegen.addNewDecoder(typeLiteral.cacheKey, decoder);
353-
}
354-
355-
public static void registerFieldDecoder(Class clazz, String field, Decoder decoder) {
356-
Codegen.addNewDecoder(field + "@" + TypeLiteral.generateDecoderCacheKey(clazz), decoder);
357-
}
358-
359-
public static void registerFieldDecoder(TypeLiteral typeLiteral, String field, Decoder decoder) {
360-
Codegen.addNewDecoder(field + "@" + typeLiteral.cacheKey, decoder);
361-
}
362-
363-
public static void registerExtension(Extension extension) {
364-
ExtensionManager.registerExtension(extension);
365-
}
366-
367347
public static void enableStrictMode() {
368348
Codegen.enableStrictMode();
369349
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package com.jsoniter;
2+
3+
import java.io.IOException;
4+
import java.lang.reflect.Constructor;
5+
import java.util.*;
6+
7+
public class ReflectionDecoder implements Decoder {
8+
9+
private static Object NOT_SET = new Object();
10+
private Constructor ctor;
11+
private Map<String, Binding> allBindings = new HashMap<String, Binding>();
12+
private List<Binding> ctorParams = new ArrayList<Binding>();
13+
private ThreadLocal<Object[]> tempTls;
14+
private ThreadLocal<Object[]> ctorArgsTls;
15+
private List<Binding> fields;
16+
17+
public ReflectionDecoder(Class clazz) {
18+
try {
19+
init(clazz);
20+
} catch (Exception e) {
21+
throw new RuntimeException(e);
22+
}
23+
}
24+
25+
private void init(Class clazz) throws Exception {
26+
CustomizedConstructor cctor = ExtensionManager.getCtor(clazz, true);
27+
ctorParams = cctor.parameters;
28+
int tempIdx = 0;
29+
for (Binding param : ctorParams) {
30+
param.idx = tempIdx;
31+
for (String fromName : param.fromNames) {
32+
allBindings.put(fromName, param);
33+
}
34+
tempIdx++;
35+
}
36+
this.ctor = cctor.ctor;
37+
fields = ExtensionManager.getFields(clazz, true);
38+
for (Binding field : fields) {
39+
field.idx = tempIdx;
40+
for (String fromName : field.fromNames) {
41+
allBindings.put(fromName, field);
42+
}
43+
tempIdx++;
44+
}
45+
if (!ctorParams.isEmpty()) {
46+
final int tempCount = tempIdx;
47+
tempTls = new ThreadLocal<Object[]>() {
48+
@Override
49+
protected Object[] initialValue() {
50+
return new Object[tempCount];
51+
}
52+
};
53+
ctorArgsTls = new ThreadLocal<Object[]>() {
54+
@Override
55+
protected Object[] initialValue() {
56+
return new Object[ctorParams.size()];
57+
}
58+
};
59+
}
60+
}
61+
62+
@Override
63+
public Object decode(JsonIterator iter) throws IOException {
64+
try {
65+
if (ctorParams.isEmpty()) {
66+
return decodeWithoutCtorBinding(iter);
67+
} else {
68+
return decodeWithCtorBinding(iter);
69+
}
70+
} catch (Exception e) {
71+
throw new RuntimeException(e);
72+
}
73+
}
74+
75+
private Object decodeWithCtorBinding(JsonIterator iter) throws Exception {
76+
Object[] temp = tempTls.get();
77+
Arrays.fill(temp, NOT_SET);
78+
for (String fieldName = iter.readObject(); fieldName != null; fieldName = iter.readObject()) {
79+
Binding binding = allBindings.get(fieldName);
80+
if (binding == null) {
81+
iter.skip();
82+
continue;
83+
}
84+
temp[binding.idx] = iter.read(binding.valueTypeLiteral);
85+
}
86+
Object[] ctorArgs = ctorArgsTls.get();
87+
Arrays.fill(ctorArgs, NOT_SET);
88+
for (int i = 0; i < ctorParams.size(); i++) {
89+
Object arg = temp[ctorParams.get(i).idx];
90+
if (arg != NOT_SET) {
91+
ctorArgs[i] = arg;
92+
}
93+
}
94+
Object obj = ctor.newInstance(ctorArgs);
95+
for (Binding field : fields) {
96+
Object val = temp[field.idx];
97+
if (val != NOT_SET) {
98+
field.field.set(obj, val);
99+
}
100+
}
101+
return obj;
102+
}
103+
104+
private Object decodeWithoutCtorBinding(JsonIterator iter) throws Exception {
105+
Object obj = ctor.newInstance();
106+
for (String fieldName = iter.readObject(); fieldName != null; fieldName = iter.readObject()) {
107+
Binding binding = allBindings.get(fieldName);
108+
if (binding == null) {
109+
iter.skip();
110+
continue;
111+
}
112+
if (binding.field != null) {
113+
binding.field.set(obj, iter.read(binding.valueTypeLiteral));
114+
}
115+
}
116+
return obj;
117+
}
118+
}

src/main/java/com/jsoniter/annotation/JsoniterAnnotationSupport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
public class JsoniterAnnotationSupport extends EmptyExtension {
1313

1414
public static void enable() {
15-
JsonIterator.registerExtension(new JsoniterAnnotationSupport());
15+
ExtensionManager.registerExtension(new JsoniterAnnotationSupport());
1616
}
1717

1818
@Override

0 commit comments

Comments
 (0)