Skip to content

Commit d97d10d

Browse files
committed
reflection support map
1 parent ce183e4 commit d97d10d

10 files changed

Lines changed: 106 additions & 31 deletions

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ private synchronized static Decoder gen(String cacheKey, Type type) {
5050
clazz = (Class) type;
5151
}
5252
if (mode == DecodingMode.REFLECTION_MODE) {
53-
return ReflectionDecoder.create(clazz, typeArgs);
53+
return ReflectionDecoderFactory.create(clazz, typeArgs);
5454
}
5555
try {
5656
return (Decoder) Class.forName(cacheKey).newInstance();
@@ -108,6 +108,27 @@ private static Type chooseImpl(Type type) {
108108
}
109109
return new ParameterizedTypeImpl(new Type[]{compType}, null, clazz);
110110
}
111+
if (Map.class.isAssignableFrom(clazz)) {
112+
Type keyType = String.class;
113+
Type valueType = Object.class;
114+
if (typeArgs.length == 0) {
115+
// default to Map<String, Object>
116+
} else if (typeArgs.length == 2) {
117+
keyType = typeArgs[0];
118+
valueType = typeArgs[1];
119+
} else {
120+
throw new IllegalArgumentException(
121+
"can not bind to generic collection without argument types, " +
122+
"try syntax like TypeLiteral<Map<String, String>>{}");
123+
}
124+
if (keyType != String.class) {
125+
throw new IllegalArgumentException("map key must be String");
126+
}
127+
if (clazz == Map.class) {
128+
clazz = HashMap.class;
129+
}
130+
return new ParameterizedTypeImpl(new Type[]{keyType, valueType}, null, clazz);
131+
}
111132
return type;
112133
}
113134

src/main/java/com/jsoniter/CodegenImplArray.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public static String genArray(Class clazz) {
1717
throw new IllegalArgumentException("nested array not supported: " + clazz.getCanonicalName());
1818
}
1919
StringBuilder lines = new StringBuilder();
20+
append(lines, "com.jsoniter.CodegenAccess.resetExistingObject(iter);");
2021
append(lines, "if (iter.readNull()) { return null; }");
2122
append(lines, "if (!com.jsoniter.CodegenAccess.readArrayStart(iter)) {");
2223
append(lines, "return new {{comp}}[0];");
@@ -67,8 +68,8 @@ public static String genCollection(Class clazz, Type[] typeArgs) {
6768

6869
private static String genCollectionWithCapacity(Class clazz, Type compType) {
6970
StringBuilder lines = new StringBuilder();
70-
append(lines, "if (iter.readNull()) { return null; }");
7171
append(lines, "{{clazz}} col = ({{clazz}})com.jsoniter.CodegenAccess.resetExistingObject(iter);");
72+
append(lines, "if (iter.readNull()) { return null; }");
7273
append(lines, "if (!com.jsoniter.CodegenAccess.readArrayStart(iter)) {");
7374
append(lines, "return col == null ? new {{clazz}}(0): ({{clazz}})com.jsoniter.CodegenAccess.reuseCollection(col);");
7475
append(lines, "}");

src/main/java/com/jsoniter/CodegenImplMap.java

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,10 @@
77
class CodegenImplMap {
88

99
public static String genMap(Class clazz, Type[] typeArgs) {
10-
Type keyType = String.class;
11-
Type valueType = Object.class;
12-
if (typeArgs.length == 0) {
13-
// default to Map<String, Object>
14-
} else if (typeArgs.length == 2) {
15-
keyType = typeArgs[0];
16-
valueType = typeArgs[1];
17-
} else {
18-
throw new IllegalArgumentException(
19-
"can not bind to generic collection without argument types, " +
20-
"try syntax like TypeLiteral<Map<String, String>>{}");
21-
}
22-
if (keyType != String.class) {
23-
throw new IllegalArgumentException("map key must be String");
24-
}
25-
if (clazz == Map.class) {
26-
clazz = HashMap.class;
27-
}
10+
Type valueType = typeArgs[1];
2811
StringBuilder lines = new StringBuilder();
29-
append(lines, "if (iter.readNull()) { return null; }");
3012
append(lines, "{{clazz}} map = ({{clazz}})com.jsoniter.CodegenAccess.resetExistingObject(iter);");
13+
append(lines, "if (iter.readNull()) { return null; }");
3114
append(lines, "if (map == null) { map = new {{clazz}}(); }");
3215
append(lines, "if (!com.jsoniter.CodegenAccess.readObjectStart(iter)) {");
3316
append(lines, "return map;");

src/main/java/com/jsoniter/ReflectionArrayDecoder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import java.io.IOException;
77
import java.lang.reflect.Array;
88

9-
public class ReflectionArrayDecoder implements Decoder {
9+
class ReflectionArrayDecoder implements Decoder {
1010

1111
private final Class componentType;
1212
private final TypeLiteral compTypeLiteral;
@@ -18,6 +18,7 @@ public ReflectionArrayDecoder(Class clazz) {
1818

1919
@Override
2020
public Object decode(JsonIterator iter) throws IOException {
21+
CodegenAccess.resetExistingObject(iter);
2122
if (iter.readNull()) {
2223
return null;
2324
}

src/main/java/com/jsoniter/ReflectionCollectionDecoder.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@
44
import com.jsoniter.spi.TypeLiteral;
55

66
import java.io.IOException;
7+
import java.lang.reflect.Constructor;
78
import java.lang.reflect.Type;
89
import java.util.Collection;
910

10-
public class ReflectionCollectionDecoder implements Decoder {
11-
private final Class clazz;
11+
class ReflectionCollectionDecoder implements Decoder {
1212
private final TypeLiteral compTypeLiteral;
13+
private final Constructor ctor;
1314

1415
public ReflectionCollectionDecoder(Class clazz, Type[] typeArgs) {
15-
this.clazz = clazz;
16+
try {
17+
ctor = clazz.getConstructor();
18+
} catch (NoSuchMethodException e) {
19+
throw new JsonException(e);
20+
}
1621
compTypeLiteral = TypeLiteral.create(typeArgs[0]);
1722
}
1823

@@ -26,10 +31,15 @@ public Object decode(JsonIterator iter) throws IOException {
2631
}
2732

2833
private Object decode_(JsonIterator iter) throws Exception {
34+
Collection col = (Collection) CodegenAccess.resetExistingObject(iter);
2935
if (iter.readNull()) {
3036
return null;
3137
}
32-
Collection col = (Collection) this.clazz.newInstance();
38+
if (col == null) {
39+
col = (Collection) this.ctor.newInstance();
40+
} else {
41+
col.clear();
42+
}
3343
while (iter.readArray()) {
3444
col.add(CodegenAccess.read(iter, compTypeLiteral));
3545
}

src/main/java/com/jsoniter/ReflectionDecoder.java renamed to src/main/java/com/jsoniter/ReflectionDecoderFactory.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
import java.io.IOException;
77
import java.lang.reflect.Type;
88
import java.util.Collection;
9+
import java.util.Map;
910

10-
public class ReflectionDecoder {
11+
public class ReflectionDecoderFactory {
1112
public static Decoder create(Class clazz, Type... typeArgs) {
1213
final TypeLiteral typeLiteral = TypeLiteral.create(clazz);
1314
TypeLiteral.NativeType nativeType = typeLiteral.getNativeType();
@@ -25,6 +26,9 @@ public Object decode(JsonIterator iter) throws IOException {
2526
if (Collection.class.isAssignableFrom(clazz)) {
2627
return new ReflectionCollectionDecoder(clazz, typeArgs);
2728
}
29+
if (Map.class.isAssignableFrom(clazz)) {
30+
return new ReflectionMapDecoder(clazz, typeArgs);
31+
}
2832
return new ReflectionObjectDecoder(clazz);
2933
}
3034
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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.Constructor;
8+
import java.lang.reflect.Type;
9+
import java.util.Map;
10+
11+
class ReflectionMapDecoder implements Decoder {
12+
13+
private final Constructor ctor;
14+
private final TypeLiteral valueTypeLiteral;
15+
16+
public ReflectionMapDecoder(Class clazz, Type[] typeArgs) {
17+
try {
18+
ctor = clazz.getConstructor();
19+
} catch (NoSuchMethodException e) {
20+
throw new JsonException(e);
21+
}
22+
valueTypeLiteral = TypeLiteral.create(typeArgs[1]);
23+
}
24+
25+
@Override
26+
public Object decode(JsonIterator iter) throws IOException {
27+
try {
28+
return decode_(iter);
29+
} catch (Exception e) {
30+
throw new JsonException(e);
31+
}
32+
}
33+
34+
private Object decode_(JsonIterator iter) throws Exception {
35+
Map map = (Map) CodegenAccess.resetExistingObject(iter);
36+
if (iter.readNull()) {
37+
return null;
38+
}
39+
if (map == null) {
40+
map = (Map) ctor.newInstance();
41+
}
42+
if (!CodegenAccess.readObjectStart(iter)) {
43+
return map;
44+
}
45+
String field = CodegenAccess.readObjectFieldAsString(iter);
46+
map.put(field, CodegenAccess.read(iter, valueTypeLiteral));
47+
while (CodegenAccess.nextToken(iter) == ',') {
48+
field = CodegenAccess.readObjectFieldAsString(iter);
49+
map.put(field, CodegenAccess.read(iter, valueTypeLiteral));
50+
}
51+
return map;
52+
}
53+
}

src/main/java/com/jsoniter/ReflectionObjectDecoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import java.io.IOException;
66
import java.util.*;
77

8-
public class ReflectionObjectDecoder implements Decoder {
8+
class ReflectionObjectDecoder implements Decoder {
99

1010
private static Object NOT_SET = new Object() {
1111
@Override

src/test/java/com/jsoniter/TestArray.java

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

1414
static {
15-
JsonIterator.setMode(DecodingMode.REFLECTION_MODE);
15+
// JsonIterator.setMode(DecodingMode.REFLECTION_MODE);
1616
}
1717

1818
public void test_empty_array() throws IOException {

src/test/java/com/jsoniter/TestGenerics.java

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

3-
import com.jsoniter.annotation.JsonProperty;
43
import com.jsoniter.spi.Binding;
54
import com.jsoniter.spi.ClassDescriptor;
65
import com.jsoniter.spi.ExtensionManager;
76
import com.jsoniter.spi.TypeLiteral;
87
import junit.framework.TestCase;
98

109
import java.io.IOException;
11-
import java.lang.reflect.*;
1210
import java.util.*;
1311

1412
import static org.junit.Assert.assertArrayEquals;
1513

1614
public class TestGenerics extends TestCase {
1715

16+
static {
17+
// JsonIterator.setMode(DecodingMode.REFLECTION_MODE);
18+
}
19+
1820
public void test_int_list() throws IOException {
1921
JsonIterator iter = JsonIterator.parse("[1,2,3]");
2022
List<Integer> val = iter.read(new TypeLiteral<ArrayList<Integer>>() {

0 commit comments

Comments
 (0)