Skip to content

Commit 268588e

Browse files
committed
support primitive type customization
1 parent 11198ae commit 268588e

File tree

7 files changed

+212
-55
lines changed

7 files changed

+212
-55
lines changed

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

Lines changed: 91 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class Codegen {
1818
put("byte", "iter.readShort()");
1919
put("short", "iter.readShort()");
2020
put("int", "iter.readInt()");
21+
put("char", "iter.readInt()");
2122
put("long", "iter.readLong()");
2223
put(Float.class.getName(), "Float.valueOf(iter.readFloat())");
2324
put(Double.class.getName(), "Double.valueOf(iter.readDouble())");
@@ -161,10 +162,12 @@ public static void addNewDecoder(String cacheKey, Decoder decoder) {
161162
private static String genObject(Class clazz, String cacheKey) {
162163
Map<Integer, Object> map = new HashMap<Integer, Object>();
163164
for (Field field : clazz.getFields()) {
164-
Decoder decoder = createFieldDecoder(cacheKey, field);
165165
String[] alternativeFieldNames = null;
166-
if (decoder instanceof FieldDecoder) {
167-
alternativeFieldNames = ((FieldDecoder) decoder).getAlternativeFieldNames();
166+
for (FieldDecoderFactory fieldDecoderFactory : fieldDecoderFactories) {
167+
alternativeFieldNames = fieldDecoderFactory.getAlternativeFieldNames(field);
168+
if (alternativeFieldNames != null) {
169+
break;
170+
}
168171
}
169172
if (alternativeFieldNames == null) {
170173
alternativeFieldNames = new String[]{field.getName()};
@@ -217,8 +220,7 @@ private static String genObject(Class clazz, String cacheKey) {
217220
return lines.toString().replace("{{clazz}}", clazz.getName());
218221
}
219222

220-
private static Decoder createFieldDecoder(String cacheKey, Field field) {
221-
String fieldCacheKey = field.getName() + "@" + cacheKey;
223+
private static Decoder createFieldDecoder(String fieldCacheKey, Field field) {
222224
for (FieldDecoderFactory fieldDecoderFactory : fieldDecoderFactories) {
223225
Decoder decoder = fieldDecoderFactory.createDecoder(field);
224226
if (decoder != null) {
@@ -246,14 +248,67 @@ private static void addFieldDispatch(StringBuilder lines, int len, int i, Map<By
246248
}
247249

248250
private static void genField(StringBuilder lines, Field field, String cacheKey) {
249-
String fieldTypeName = field.getType().getCanonicalName();
251+
Class<?> fieldType = field.getType();
252+
String fieldTypeName = fieldType.getCanonicalName();
250253
String fieldCacheKey = field.getName() + "@" + cacheKey;
251-
Decoder decoder = cache.get(fieldCacheKey);
252-
boolean useCustomizedDecoder = decoder != null;
253-
if (useCustomizedDecoder && decoder instanceof FieldDecoder) {
254-
useCustomizedDecoder = ((FieldDecoder) decoder).useDefaultDecoder();
255-
}
256-
if (useCustomizedDecoder) {
254+
Decoder decoder = createFieldDecoder(fieldCacheKey, field);
255+
if (decoder != null) {
256+
if (fieldType == boolean.class) {
257+
if (!(decoder instanceof Decoder.BooleanDecoder)) {
258+
throw new RuntimeException("decoder for field " + field + "must implement Decoder.BooleanDecoder");
259+
}
260+
append(lines, String.format("obj.%s = iter.readBoolean(\"%s\");", field.getName(), fieldCacheKey));
261+
return;
262+
}
263+
if (fieldType == byte.class) {
264+
if (!(decoder instanceof Decoder.ShortDecoder)) {
265+
throw new RuntimeException("decoder for field " + field + "must implement Decoder.ShortDecoder");
266+
}
267+
append(lines, String.format("obj.%s = iter.readShort(\"%s\");", field.getName(), fieldCacheKey));
268+
return;
269+
}
270+
if (fieldType == short.class) {
271+
if (!(decoder instanceof Decoder.ShortDecoder)) {
272+
throw new RuntimeException("decoder for field " + field + "must implement Decoder.ShortDecoder");
273+
}
274+
append(lines, String.format("obj.%s = iter.readShort(\"%s\");", field.getName(), fieldCacheKey));
275+
return;
276+
}
277+
if (fieldType == char.class) {
278+
if (!(decoder instanceof Decoder.IntDecoder)) {
279+
throw new RuntimeException("decoder for field " + field + "must implement Decoder.IntDecoder");
280+
}
281+
append(lines, String.format("obj.%s = iter.readInt(\"%s\");", field.getName(), fieldCacheKey));
282+
return;
283+
}
284+
if (fieldType == int.class) {
285+
if (!(decoder instanceof Decoder.IntDecoder)) {
286+
throw new RuntimeException("decoder for field " + field + "must implement Decoder.IntDecoder");
287+
}
288+
append(lines, String.format("obj.%s = iter.readInt(\"%s\");", field.getName(), fieldCacheKey));
289+
return;
290+
}
291+
if (fieldType == long.class) {
292+
if (!(decoder instanceof Decoder.LongDecoder)) {
293+
throw new RuntimeException("decoder for field " + field + "must implement Decoder.LongDecoder");
294+
}
295+
append(lines, String.format("obj.%s = iter.readLong(\"%s\");", field.getName(), fieldCacheKey));
296+
return;
297+
}
298+
if (fieldType == float.class) {
299+
if (!(decoder instanceof Decoder.FloatDecoder)) {
300+
throw new RuntimeException("decoder for field " + field + "must implement Decoder.FloatDecoder");
301+
}
302+
append(lines, String.format("obj.%s = iter.readFloat(\"%s\");", field.getName(), fieldCacheKey));
303+
return;
304+
}
305+
if (fieldType == double.class) {
306+
if (!(decoder instanceof Decoder.DoubleDecoder)) {
307+
throw new RuntimeException("decoder for field " + field + "must implement Decoder.DoubleDecoder");
308+
}
309+
append(lines, String.format("obj.%s = iter.readDouble(\"%s\");", field.getName(), fieldCacheKey));
310+
return;
311+
}
257312
append(lines, String.format("obj.%s = (%s)iter.read(\"%s\", %s.class);",
258313
field.getName(), fieldTypeName, fieldCacheKey, fieldTypeName));
259314
return;
@@ -433,4 +488,28 @@ private static void append(StringBuilder lines, String str) {
433488
public static void addFieldDecoderFactory(FieldDecoderFactory fieldDecoderFactory) {
434489
fieldDecoderFactories.add(fieldDecoderFactory);
435490
}
491+
492+
public static Decoder.IntDecoder getIntDecoder(String cacheKey) {
493+
return (Decoder.IntDecoder) cache.get(cacheKey);
494+
}
495+
496+
public static Decoder.BooleanDecoder getBooleanDecoder(String cacheKey) {
497+
return (Decoder.BooleanDecoder) cache.get(cacheKey);
498+
}
499+
500+
public static Decoder.ShortDecoder getShortDecoder(String cacheKey) {
501+
return (Decoder.ShortDecoder) cache.get(cacheKey);
502+
}
503+
504+
public static Decoder.LongDecoder getLongDecoder(String cacheKey) {
505+
return (Decoder.LongDecoder) cache.get(cacheKey);
506+
}
507+
508+
public static Decoder.FloatDecoder getFloatDecoder(String cacheKey) {
509+
return (Decoder.FloatDecoder) cache.get(cacheKey);
510+
}
511+
512+
public static Decoder.DoubleDecoder getDoubleDecoder(String cacheKey) {
513+
return (Decoder.DoubleDecoder) cache.get(cacheKey);
514+
}
436515
}

src/main/java/com/jsoniter/Decoder.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,28 @@ public interface Decoder {
1313
* @throws IOException
1414
*/
1515
Object decode(Type type, Jsoniter iter) throws IOException;
16+
17+
interface BooleanDecoder extends Decoder {
18+
boolean decodeBoolean(Jsoniter iter) throws IOException;
19+
}
20+
21+
interface ShortDecoder extends Decoder {
22+
short decodeShort(Jsoniter iter) throws IOException;
23+
}
24+
25+
interface IntDecoder extends Decoder {
26+
int decodeInt(Jsoniter iter) throws IOException;
27+
}
28+
29+
interface LongDecoder extends Decoder {
30+
long decodeLong(Jsoniter iter) throws IOException;
31+
}
32+
33+
interface FloatDecoder extends Decoder {
34+
float decodeFloat(Jsoniter iter) throws IOException;
35+
}
36+
37+
interface DoubleDecoder extends Decoder {
38+
double decodeDouble(Jsoniter iter) throws IOException;
39+
}
1640
}

src/main/java/com/jsoniter/FieldDecoderFactory.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,11 @@ public interface FieldDecoderFactory {
1010
* @return null, if no special customization needed
1111
*/
1212
Decoder createDecoder(Field field);
13+
14+
/**
15+
* Customize the field map to
16+
* @param field the field reflection object
17+
* @return null, if fallback to default behavior
18+
*/
19+
String[] getAlternativeFieldNames(Field field);
1320
}

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

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import java.util.HashMap;
1010
import java.util.Map;
1111

12+
import static java.lang.Character.*;
13+
1214
public class Jsoniter implements Closeable {
1315

1416
final static int[] digits = new int[256];
@@ -28,7 +30,7 @@ public class Jsoniter implements Closeable {
2830
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2931
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3032
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
33+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
3234
InputStream in;
3335
byte[] buf;
3436
int head;
@@ -159,6 +161,10 @@ public final boolean readNull() throws IOException {
159161
return false;
160162
}
161163

164+
public final boolean readBoolean(String cacheKey) throws IOException {
165+
return Codegen.getBooleanDecoder(cacheKey).decodeBoolean(this);
166+
}
167+
162168
public final boolean readBoolean() throws IOException {
163169
byte c = readByte();
164170
switch (c) {
@@ -173,6 +179,10 @@ public final boolean readBoolean() throws IOException {
173179
}
174180
}
175181

182+
public final short readShort(String cacheKey) throws IOException {
183+
return Codegen.getShortDecoder(cacheKey).decodeShort(this);
184+
}
185+
176186
public final short readShort() throws IOException {
177187
int v = readInt();
178188
if (Short.MIN_VALUE <= v && v <= Short.MAX_VALUE) {
@@ -182,6 +192,10 @@ public final short readShort() throws IOException {
182192
}
183193
}
184194

195+
public final int readInt(String cacheKey) throws IOException {
196+
return Codegen.getIntDecoder(cacheKey).decodeInt(this);
197+
}
198+
185199
public final int readInt() throws IOException {
186200
byte c = readByte();
187201
if (c == '-') {
@@ -215,6 +229,10 @@ public final int readUnsignedInt() throws IOException {
215229
return result;
216230
}
217231

232+
public final long readLong(String cacheKey) throws IOException {
233+
return Codegen.getLongDecoder(cacheKey).decodeLong(this);
234+
}
235+
218236
public final long readLong() throws IOException {
219237
byte c = readByte();
220238
if (c == '-') {
@@ -411,22 +429,22 @@ public final byte[] readBase64() throws IOException {
411429
}
412430

413431
int num = 0;
414-
if (i + 1 < end && base64Tbl[slice.data[i+1]] != -1) {
415-
b = b | ((base64Tbl[slice.data[i+1]] & 0xFF) << 12);
432+
if (i + 1 < end && base64Tbl[slice.data[i + 1]] != -1) {
433+
b = b | ((base64Tbl[slice.data[i + 1]] & 0xFF) << 12);
416434
num++;
417435
}
418-
if (i + 2 < end && base64Tbl[slice.data[i+2]] != -1) {
419-
b = b | ((base64Tbl[slice.data[i+2]] & 0xFF) << 6);
436+
if (i + 2 < end && base64Tbl[slice.data[i + 2]] != -1) {
437+
b = b | ((base64Tbl[slice.data[i + 2]] & 0xFF) << 6);
420438
num++;
421439
}
422-
if (i + 3 < end && base64Tbl[slice.data[i+3]] != -1) {
423-
b = b | (base64Tbl[slice.data[i+3]] & 0xFF);
440+
if (i + 3 < end && base64Tbl[slice.data[i + 3]] != -1) {
441+
b = b | (base64Tbl[slice.data[i + 3]] & 0xFF);
424442
num++;
425443
}
426444

427445
while (num > 0) {
428446
int c = (b & 0xFF0000) >> 16;
429-
buffer.write((char)c);
447+
buffer.write((char) c);
430448
b <<= 8;
431449
num--;
432450
}
@@ -571,14 +589,23 @@ final String readStringSlowPath() throws IOException {
571589
((byte) 0x80 << 12) ^
572590
((byte) 0x80 << 6) ^
573591
((byte) 0x80 << 0))));
574-
reusableChars[j++] = Character.highSurrogate(uc);
575-
reusableChars[j++] = Character.lowSurrogate(uc);
592+
reusableChars[j++] = highSurrogate(uc);
593+
reusableChars[j++] = lowSurrogate(uc);
576594
} else {
577595
throw new RuntimeException("unexpected input");
578596
}
579597
}
580598
}
581599

600+
private static char highSurrogate(int codePoint) {
601+
return (char) ((codePoint >>> 10)
602+
+ (MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10)));
603+
}
604+
605+
private static char lowSurrogate(int codePoint) {
606+
return (char) ((codePoint & 0x3ff) + MIN_LOW_SURROGATE);
607+
}
608+
582609
public final String readObject() throws IOException {
583610
byte c = nextToken();
584611
switch (c) {
@@ -711,10 +738,18 @@ final String readNumber() throws IOException {
711738
return new String(reusableChars, 0, j);
712739
}
713740

741+
public final float readFloat(String cacheKey) throws IOException {
742+
return Codegen.getFloatDecoder(cacheKey).decodeFloat(this);
743+
}
744+
714745
public final float readFloat() throws IOException {
715746
return Float.valueOf(readNumber());
716747
}
717748

749+
public final double readDouble(String cacheKey) throws IOException {
750+
return Codegen.getDoubleDecoder(cacheKey).decodeDouble(this);
751+
}
752+
718753
public final double readDouble() throws IOException {
719754
return Double.valueOf(readNumber());
720755
}
Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package com.jsoniter.annotation.jsoniter;
22

3-
import com.jsoniter.*;
3+
import com.jsoniter.Decoder;
4+
import com.jsoniter.FieldDecoderFactory;
5+
import com.jsoniter.Jsoniter;
46

5-
import java.io.IOException;
67
import java.lang.reflect.Field;
7-
import java.lang.reflect.Type;
88

99
public class JsoniterAnnotationSupport implements FieldDecoderFactory {
1010

@@ -14,6 +14,11 @@ public static void enable() {
1414

1515
@Override
1616
public Decoder createDecoder(final Field field) {
17+
return null;
18+
}
19+
20+
@Override
21+
public String[] getAlternativeFieldNames(Field field) {
1722
JsonProperty annotation = field.getAnnotation(JsonProperty.class);
1823
if (annotation == null) {
1924
return null;
@@ -23,23 +28,6 @@ public Decoder createDecoder(final Field field) {
2328
alternativeField = field.getName();
2429
}
2530
final String[] alternativeFields = new String[]{alternativeField};
26-
final String fieldCacheKey = TypeLiteral.generateCacheKey(field.getGenericType());
27-
final Class<?> fieldType = field.getType();
28-
return new FieldDecoder() {
29-
@Override
30-
public String[] getAlternativeFieldNames() {
31-
return alternativeFields;
32-
}
33-
34-
@Override
35-
public boolean useDefaultDecoder() {
36-
return false;
37-
}
38-
39-
@Override
40-
public Object decode(Type type, Jsoniter iter) throws IOException {
41-
return iter.read(fieldCacheKey, fieldType);
42-
}
43-
};
31+
return alternativeFields;
4432
}
4533
}

src/test/java/com/jsoniter/CustomizedObject.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
public class CustomizedObject {
44
public String field2;
55
public String field1;
6+
public int field3;
67

78
@Override
89
public boolean equals(Object o) {
910
if (this == o) return true;
11+
if (o == null || getClass() != o.getClass()) return false;
1012

1113
CustomizedObject that = (CustomizedObject) o;
1214

15+
if (field3 != that.field3) return false;
1316
if (field2 != null ? !field2.equals(that.field2) : that.field2 != null) return false;
1417
return field1 != null ? field1.equals(that.field1) : that.field1 == null;
1518

@@ -19,6 +22,7 @@ public boolean equals(Object o) {
1922
public int hashCode() {
2023
int result = field2 != null ? field2.hashCode() : 0;
2124
result = 31 * result + (field1 != null ? field1.hashCode() : 0);
25+
result = 31 * result + field3;
2226
return result;
2327
}
2428
}

0 commit comments

Comments
 (0)