Skip to content

Commit e17e2df

Browse files
committed
make constructor customizatable
1 parent 929645c commit e17e2df

File tree

6 files changed

+84
-54
lines changed

6 files changed

+84
-54
lines changed

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

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class Codegen {
4141
add(Vector.class);
4242
}};
4343
static volatile Map<String, Decoder> cache = new HashMap<String, Decoder>();
44-
static List<Extension> fieldDecoderFactories = new ArrayList<Extension>();
44+
static List<Extension> extensions = new ArrayList<Extension>();
4545
static ClassPool pool = ClassPool.getDefault();
4646

4747
static Decoder getDecoder(String cacheKey, Type type, Type... typeArgs) {
@@ -164,10 +164,51 @@ public static void addNewDecoder(String cacheKey, Decoder decoder) {
164164
}
165165

166166
private static String genObject(Class clazz, String cacheKey) {
167-
Map<Integer, Object> map = new HashMap<Integer, Object>();
167+
Map<Integer, Object> trieTree = buildTriTree(clazz);
168+
String newInstanceCode = null;
169+
for (Extension extension : extensions) {
170+
newInstanceCode = extension.codegenNewInstance(clazz);
171+
if (newInstanceCode != null) {
172+
break;
173+
}
174+
}
175+
if (newInstanceCode == null) {
176+
newInstanceCode = "new " + clazz.getCanonicalName() + "()";
177+
}
178+
if (trieTree.isEmpty()) {
179+
StringBuilder lines = new StringBuilder();
180+
append(lines, "public Object decode(com.jsoniter.Jsoniter iter) {");
181+
append(lines, "{{clazz}} obj = {{newInst}};");
182+
append(lines, "iter.skip();");
183+
append(lines, "return obj;");
184+
append(lines, "}");
185+
return lines.toString().replace("{{clazz}}", clazz.getName()).replace("{{newInst}}", newInstanceCode);
186+
}
187+
StringBuilder lines = new StringBuilder();
188+
append(lines, "public Object decode(com.jsoniter.Jsoniter iter) {");
189+
append(lines, "{{clazz}} obj = {{newInst}};");
190+
append(lines, "for (com.jsoniter.Slice field = iter.readObjectAsSlice(); field != null; field = iter.readObjectAsSlice()) {");
191+
append(lines, "switch (field.len) {");
192+
for (Map.Entry<Integer, Object> entry : trieTree.entrySet()) {
193+
Integer len = entry.getKey();
194+
append(lines, "case " + len + ": ");
195+
Map<Byte, Object> current = (Map<Byte, Object>) entry.getValue();
196+
addFieldDispatch(lines, len, 0, current, cacheKey);
197+
append(lines, "break;");
198+
}
199+
append(lines, "}");
200+
append(lines, "iter.skip();");
201+
append(lines, "}");
202+
append(lines, "return obj;");
203+
append(lines, "}");
204+
return lines.toString().replace("{{clazz}}", clazz.getName()).replace("{{newInst}}", newInstanceCode);
205+
}
206+
207+
private static Map<Integer, Object> buildTriTree(Class clazz) {
208+
Map<Integer, Object> trieTree = new HashMap<Integer, Object>();
168209
for (Field field : clazz.getFields()) {
169210
String[] alternativeFieldNames = null;
170-
for (Extension extension : fieldDecoderFactories) {
211+
for (Extension extension : extensions) {
171212
alternativeFieldNames = extension.getAlternativeFieldNames(field);
172213
if (alternativeFieldNames != null) {
173214
break;
@@ -178,10 +219,10 @@ private static String genObject(Class clazz, String cacheKey) {
178219
}
179220
for (String alternativeFieldName : alternativeFieldNames) {
180221
byte[] fieldName = alternativeFieldName.getBytes();
181-
Map<Byte, Object> current = (Map<Byte, Object>) map.get(fieldName.length);
222+
Map<Byte, Object> current = (Map<Byte, Object>) trieTree.get(fieldName.length);
182223
if (current == null) {
183224
current = new HashMap<Byte, Object>();
184-
map.put(fieldName.length, current);
225+
trieTree.put(fieldName.length, current);
185226
}
186227
for (int i = 0; i < fieldName.length - 1; i++) {
187228
byte b = fieldName[i];
@@ -195,37 +236,11 @@ private static String genObject(Class clazz, String cacheKey) {
195236
current.put(fieldName[fieldName.length - 1], field);
196237
}
197238
}
198-
if (map.isEmpty()) {
199-
StringBuilder lines = new StringBuilder();
200-
append(lines, "public Object decode(com.jsoniter.Jsoniter iter) {");
201-
append(lines, "{{clazz}} obj = new {{clazz}}();");
202-
append(lines, "iter.skip();");
203-
append(lines, "return obj;");
204-
append(lines, "}");
205-
return lines.toString().replace("{{clazz}}", clazz.getName());
206-
}
207-
StringBuilder lines = new StringBuilder();
208-
append(lines, "public Object decode(com.jsoniter.Jsoniter iter) {");
209-
append(lines, "{{clazz}} obj = new {{clazz}}();");
210-
append(lines, "for (com.jsoniter.Slice field = iter.readObjectAsSlice(); field != null; field = iter.readObjectAsSlice()) {");
211-
append(lines, "switch (field.len) {");
212-
for (Map.Entry<Integer, Object> entry : map.entrySet()) {
213-
Integer len = entry.getKey();
214-
append(lines, "case " + len + ": ");
215-
Map<Byte, Object> current = (Map<Byte, Object>) entry.getValue();
216-
addFieldDispatch(lines, len, 0, current, cacheKey);
217-
append(lines, "break;");
218-
}
219-
append(lines, "}");
220-
append(lines, "iter.skip();");
221-
append(lines, "}");
222-
append(lines, "return obj;");
223-
append(lines, "}");
224-
return lines.toString().replace("{{clazz}}", clazz.getName());
239+
return trieTree;
225240
}
226241

227242
private static Decoder createFieldDecoder(String fieldCacheKey, Field field) {
228-
for (Extension extension : fieldDecoderFactories) {
243+
for (Extension extension : extensions) {
229244
Decoder decoder = extension.createDecoder(field);
230245
if (decoder != null) {
231246
addNewDecoder(fieldCacheKey, decoder);
@@ -480,8 +495,8 @@ private static void append(StringBuilder lines, String str) {
480495
lines.append("\n");
481496
}
482497

483-
public static void addFieldDecoderFactory(Extension extension) {
484-
fieldDecoderFactories.add(extension);
498+
public static void registerExtension(Extension extension) {
499+
extensions.add(extension);
485500
}
486501

487502
public static Decoder.IntDecoder getIntDecoder(String cacheKey) {

src/main/java/com/jsoniter/EmptyExtension.java

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

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

56
public class EmptyExtension implements Extension {
67

@@ -13,4 +14,9 @@ public Decoder createDecoder(Field field) {
1314
public String[] getAlternativeFieldNames(Field field) {
1415
return null;
1516
}
17+
18+
@Override
19+
public String codegenNewInstance(Type type) {
20+
return null;
21+
}
1622
}

src/main/java/com/jsoniter/Extension.java

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

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

56
public interface Extension {
67
/**
@@ -13,8 +14,17 @@ public interface Extension {
1314

1415
/**
1516
* Customize the field map to
17+
*
1618
* @param field the field reflection object
1719
* @return null, if fallback to default behavior
1820
*/
1921
String[] getAlternativeFieldNames(Field field);
22+
23+
/**
24+
* Generate source code for creating new instance
25+
*
26+
* @param type the type of new object to create
27+
* @return generated source code
28+
*/
29+
String codegenNewInstance(Type type);
2030
}

src/main/java/com/jsoniter/Jsoniter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,7 @@ public static void clearDecoders() {
10331033
Codegen.cache.clear();
10341034
}
10351035

1036-
public static void registerFieldDecoderFactory(Extension extension) {
1037-
Codegen.addFieldDecoderFactory(extension);
1036+
public static void registerExtension(Extension extension) {
1037+
Codegen.registerExtension(extension);
10381038
}
10391039
}

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

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
package com.jsoniter.annotation.jsoniter;
22

3-
import com.jsoniter.Decoder;
4-
import com.jsoniter.Extension;
3+
import com.jsoniter.EmptyExtension;
54
import com.jsoniter.Jsoniter;
65

76
import java.lang.reflect.Field;
87

9-
public class JsoniterAnnotationSupport implements Extension {
8+
public class JsoniterAnnotationSupport extends EmptyExtension {
109

1110
public static void enable() {
12-
Jsoniter.registerFieldDecoderFactory(new JsoniterAnnotationSupport());
13-
}
14-
15-
@Override
16-
public Decoder createDecoder(final Field field) {
17-
return null;
11+
Jsoniter.registerExtension(new JsoniterAnnotationSupport());
1812
}
1913

2014
@Override

src/test/java/com/jsoniter/TestCustomize.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import java.io.IOException;
66
import java.lang.reflect.Field;
7+
import java.lang.reflect.Type;
78
import java.util.Date;
89

910
public class TestCustomize extends TestCase {
@@ -33,7 +34,7 @@ public Object decode(Jsoniter iter) throws IOException {
3334
}
3435

3536
public void test_customize_all_fields() throws IOException {
36-
Jsoniter.registerFieldDecoderFactory(new Extension() {
37+
Jsoniter.registerExtension(new EmptyExtension() {
3738
@Override
3839
public Decoder createDecoder(Field field) {
3940
if (field.getDeclaringClass() == CustomizedObject.class && field.getName().equals("field1")) {
@@ -47,19 +48,14 @@ public Object decode(Jsoniter iter) throws IOException {
4748
}
4849
return null;
4950
}
50-
51-
@Override
52-
public String[] getAlternativeFieldNames(Field field) {
53-
return null;
54-
}
5551
});
5652
Jsoniter iter = Jsoniter.parse("{'field1': 100}".replace('\'', '"'));
5753
CustomizedObject myObject = iter.read(CustomizedObject.class);
5854
assertEquals("100", myObject.field1);
5955
}
6056

6157
public void test_change_field_name() throws IOException {
62-
Jsoniter.registerFieldDecoderFactory(new Extension() {
58+
Jsoniter.registerExtension(new EmptyExtension() {
6359
@Override
6460
public Decoder createDecoder(Field field) {
6561
if (field.getDeclaringClass() == CustomizedObject.class && field.getName().equals("field1")) {
@@ -107,7 +103,16 @@ public Object decode(Jsoniter iter) throws IOException {
107103
}
108104

109105
public void test_customized_constructor() throws IOException {
110-
Jsoniter iter = Jsoniter.parse("{'field1': 100}".replace('\'', '"'));
106+
Jsoniter.registerExtension(new EmptyExtension(){
107+
@Override
108+
public String codegenNewInstance(Type type) {
109+
if (type == CtorCustomizedObject.class) {
110+
return "new " + CtorCustomizedObject.class.getName() + "(iter.readInt())";
111+
}
112+
return null;
113+
}
114+
});
115+
Jsoniter iter = Jsoniter.parse("100".replace('\'', '"'));
111116
CtorCustomizedObject myObject = iter.read(CtorCustomizedObject.class);
112117
assertEquals(100, myObject.getField1());
113118
}

0 commit comments

Comments
 (0)