Skip to content

Commit a16c6f0

Browse files
committed
#84 support indention in dynamic codegen, part 3: map
1 parent 7d8caf4 commit a16c6f0

6 files changed

Lines changed: 113 additions & 34 deletions

File tree

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

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
class CodegenImplMap {
99
public static CodegenResult genMap(String cacheKey, ClassInfo classInfo) {
10+
boolean noIndention = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
1011
Type[] typeArgs = classInfo.typeArgs;
1112
boolean isCollectionValueNullable = true;
1213
if (cacheKey.endsWith("__value_not_nullable")) {
@@ -24,15 +25,27 @@ public static CodegenResult genMap(String cacheKey, ClassInfo classInfo) {
2425
ctx.append("if (obj == null) { stream.writeNull(); return; }");
2526
ctx.append("java.util.Map map = (java.util.Map)obj;");
2627
ctx.append("java.util.Iterator iter = map.entrySet().iterator();");
27-
ctx.append("if(!iter.hasNext()) { return; }");
28+
if (noIndention) {
29+
ctx.append("if(!iter.hasNext()) { return; }");
30+
} else {
31+
ctx.append("if(!iter.hasNext()) { stream.write((byte)'{', (byte)'}'); return; }");
32+
}
2833
ctx.append("java.util.Map.Entry entry = (java.util.Map.Entry)iter.next();");
29-
ctx.buffer('{');
34+
if (noIndention) {
35+
ctx.buffer('{');
36+
} else {
37+
ctx.append("stream.writeObjectStart(); stream.writeIndention();");
38+
}
3039
if (keyType == String.class) {
3140
ctx.append("stream.writeVal((java.lang.String)entry.getKey());");
3241
} else {
3342
ctx.append(String.format("com.jsoniter.output.CodegenAccess.writeMapKey(\"%s\", entry.getKey(), stream);", mapCacheKey));
3443
}
35-
ctx.append("stream.write(':');");
44+
if (noIndention) {
45+
ctx.append("stream.write(':');");
46+
} else {
47+
ctx.append("stream.write((byte)':', (byte)' ');");
48+
}
3649
if (isCollectionValueNullable) {
3750
ctx.append("if (entry.getValue() == null) { stream.writeNull(); } else {");
3851
CodegenImplNative.genWriteOp(ctx, "entry.getValue()", valueType, true);
@@ -42,13 +55,21 @@ public static CodegenResult genMap(String cacheKey, ClassInfo classInfo) {
4255
}
4356
ctx.append("while(iter.hasNext()) {");
4457
ctx.append("entry = (java.util.Map.Entry)iter.next();");
45-
ctx.append("stream.write(',');");
58+
if (noIndention) {
59+
ctx.append("stream.write(',');");
60+
} else {
61+
ctx.append("stream.writeMore();");
62+
}
4663
if (keyType == String.class) {
4764
ctx.append("stream.writeVal((java.lang.String)entry.getKey());");
4865
} else {
4966
ctx.append(String.format("com.jsoniter.output.CodegenAccess.writeMapKey(\"%s\", entry.getKey(), stream);", mapCacheKey));
5067
}
51-
ctx.append("stream.write(':');");
68+
if (noIndention) {
69+
ctx.append("stream.write(':');");
70+
} else {
71+
ctx.append("stream.write((byte)':', (byte)' ');");
72+
}
5273
if (isCollectionValueNullable) {
5374
ctx.append("if (entry.getValue() == null) { stream.writeNull(); } else {");
5475
CodegenImplNative.genWriteOp(ctx, "entry.getValue()", valueType, true);
@@ -57,7 +78,11 @@ public static CodegenResult genMap(String cacheKey, ClassInfo classInfo) {
5778
CodegenImplNative.genWriteOp(ctx, "entry.getValue()", valueType, false);
5879
}
5980
ctx.append("}");
60-
ctx.buffer('}');
81+
if (noIndention) {
82+
ctx.buffer('}');
83+
} else {
84+
ctx.append("stream.writeObjectEnd();");
85+
}
6186
ctx.append("}");
6287
return ctx;
6388
}

src/main/java/com/jsoniter/output/CodegenImplNative.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,10 +269,10 @@ public static void genWriteOp(CodegenResult ctx, String code, Type valueType, bo
269269
}
270270

271271
public static void genWriteOp(CodegenResult ctx, String code, Type valueType, boolean isNullable, boolean isCollectionValueNullable) {
272-
boolean supportBuffer = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
272+
boolean noIndention = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
273273
String cacheKey = TypeLiteral.create(valueType).getEncoderCacheKey();
274274
if (JsoniterSpi.getEncoder(cacheKey) == null) {
275-
if (supportBuffer && !isNullable && String.class == valueType) {
275+
if (noIndention && !isNullable && String.class == valueType) {
276276
ctx.buffer('"');
277277
ctx.append(String.format("com.jsoniter.output.CodegenAccess.writeStringWithoutQuote((java.lang.String)%s, stream);", code));
278278
ctx.buffer('"');

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77
class CodegenImplObject {
88
public static CodegenResult genObject(ClassInfo classInfo) {
9-
boolean supportBuffer = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
9+
boolean noIndention = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
1010
CodegenResult ctx = new CodegenResult();
1111
ClassDescriptor desc = ClassDescriptor.getEncodingClassDescriptor(classInfo, false);
1212
List<EncodeTo> encodeTos = desc.encodeTos();
1313
ctx.append(String.format("public static void encode_(%s obj, com.jsoniter.output.JsonStream stream) throws java.io.IOException {", classInfo.clazz.getCanonicalName()));
1414
if (hasFieldOutput(desc)) {
1515
int notFirst = 0;
16-
if (supportBuffer) {
16+
if (noIndention) {
1717
ctx.buffer('{');
1818
} else {
1919
ctx.append("stream.writeObjectStart();");
@@ -38,7 +38,7 @@ public static CodegenResult genObject(ClassInfo classInfo) {
3838
ctx.append(String.format("obj.%s(stream);", unwrapper.method.getName()));
3939
}
4040
}
41-
if (supportBuffer) {
41+
if (noIndention) {
4242
ctx.buffer('}');
4343
} else {
4444
ctx.append("if (notFirst) { stream.writeObjectEnd(); } else { stream.write('}'); }");
@@ -59,7 +59,7 @@ private static boolean hasFieldOutput(ClassDescriptor desc) {
5959
}
6060

6161
private static int genField(CodegenResult ctx, Binding binding, String toName, int notFirst) {
62-
boolean supportBuffer = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
62+
boolean noIndention = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
6363
String fieldCacheKey = binding.encoderCacheKey();
6464
Encoder encoder = JsoniterSpi.getEncoder(fieldCacheKey);
6565
boolean isCollectionValueNullable = binding.isCollectionValueNullable;
@@ -87,14 +87,14 @@ private static int genField(CodegenResult ctx, Binding binding, String toName, i
8787
}
8888
ctx.append(String.format("if (%s != null) {", valueAccessor));
8989
notFirst = appendComma(ctx, notFirst);
90-
if (supportBuffer) {
90+
if (noIndention) {
9191
ctx.append(CodegenResult.bufferToWriteOp("\"" + toName + "\":"));
9292
} else {
9393
ctx.append(String.format("stream.writeObjectField(\"%s\");", toName));
9494
}
9595
} else {
9696
notFirst = appendComma(ctx, notFirst);
97-
if (supportBuffer) {
97+
if (noIndention) {
9898
ctx.buffer('"');
9999
ctx.buffer(toName);
100100
ctx.buffer('"');
@@ -106,7 +106,7 @@ private static int genField(CodegenResult ctx, Binding binding, String toName, i
106106
}
107107
} else {
108108
notFirst = appendComma(ctx, notFirst);
109-
if (supportBuffer) {
109+
if (noIndention) {
110110
ctx.buffer('"');
111111
ctx.buffer(toName);
112112
ctx.buffer('"');
@@ -128,22 +128,22 @@ private static int genField(CodegenResult ctx, Binding binding, String toName, i
128128
}
129129

130130
private static int appendComma(CodegenResult ctx, int notFirst) {
131-
boolean supportBuffer = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
131+
boolean noIndention = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
132132
if (notFirst == 1) { // definitely not first
133-
if (supportBuffer) {
133+
if (noIndention) {
134134
ctx.buffer(',');
135135
} else {
136136
ctx.append("stream.writeMore();");
137137
}
138138
} else if (notFirst == 2) { // maybe not first, previous field is omitNull
139-
if (supportBuffer) {
139+
if (noIndention) {
140140
ctx.append("if (notFirst) { stream.write(','); } else { notFirst = true; }");
141141
} else {
142142
ctx.append("if (notFirst) { stream.writeMore(); } else { stream.writeIndention(); notFirst = true; }");
143143
}
144144
} else { // this is the first, do not write comma
145145
notFirst = 1;
146-
if (!supportBuffer) {
146+
if (!noIndention) {
147147
ctx.append("stream.writeIndention();");
148148
}
149149
}

src/main/java/com/jsoniter/output/ReflectionMapEncoder.java

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import java.io.IOException;
77
import java.lang.reflect.Type;
8+
import java.util.Iterator;
89
import java.util.Map;
910

1011
class ReflectionMapEncoder implements Encoder.ReflectionEncoder {
@@ -34,25 +35,38 @@ public void encode(Object obj, JsonStream stream) throws IOException {
3435
return;
3536
}
3637
Map<Object, Object> map = (Map<Object, Object>) obj;
38+
Iterator<Map.Entry<Object, Object>> iter = map.entrySet().iterator();
39+
if (!iter.hasNext()) {
40+
stream.write((byte) '{', (byte) '}');
41+
return;
42+
}
3743
stream.writeObjectStart();
3844
boolean notFirst = false;
39-
for (Map.Entry<Object, Object> entry : map.entrySet()) {
40-
if (notFirst) {
41-
stream.writeMore();
42-
} else {
43-
stream.writeIndention();
44-
notFirst = true;
45-
}
46-
if (mapKeyEncoder == null) {
47-
stream.writeObjectField((String) entry.getKey());
48-
} else {
49-
stream.writeObjectField(mapKeyEncoder.encode(entry.getKey()));
50-
}
51-
stream.writeVal(valueTypeLiteral, entry.getValue());
45+
Map.Entry<Object, Object> entry = iter.next();
46+
notFirst = writeEntry(stream, notFirst, entry);
47+
while (iter.hasNext()) {
48+
entry = iter.next();
49+
notFirst = writeEntry(stream, notFirst, entry);
5250
}
5351
stream.writeObjectEnd();
5452
}
5553

54+
private boolean writeEntry(JsonStream stream, boolean notFirst, Map.Entry<Object, Object> entry) throws IOException {
55+
if (notFirst) {
56+
stream.writeMore();
57+
} else {
58+
stream.writeIndention();
59+
notFirst = true;
60+
}
61+
if (mapKeyEncoder == null) {
62+
stream.writeObjectField((String) entry.getKey());
63+
} else {
64+
stream.writeObjectField(mapKeyEncoder.encode(entry.getKey()));
65+
}
66+
stream.writeVal(valueTypeLiteral, entry.getValue());
67+
return notFirst;
68+
}
69+
5670
@Override
5771
public Any wrap(Object obj) {
5872
Map<String, Object> map = (Map<String, Object>) obj;

src/test/java/com/jsoniter/output/TestMap.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.jsoniter.output;
22

3-
import com.jsoniter.spi.*;
3+
import com.jsoniter.spi.Config;
4+
import com.jsoniter.spi.JsoniterSpi;
5+
import com.jsoniter.spi.MapKeyEncoder;
6+
import com.jsoniter.spi.TypeLiteral;
47
import junit.framework.TestCase;
58

69
import java.io.ByteArrayOutputStream;
@@ -80,4 +83,41 @@ public String encode(Object mapKey) {
8083
}, obj);
8184
assertEquals("{\"0\":null}", output);
8285
}
86+
87+
public void test_indention() {
88+
Map<String, String> map = new HashMap<String, String>();
89+
map.put("field1", "1");
90+
map.put("field2", "2");
91+
Config dynamicCfg = new Config.Builder()
92+
.indentionStep(2)
93+
.encodingMode(EncodingMode.DYNAMIC_MODE)
94+
.build();
95+
String output = JsonStream.serialize(dynamicCfg, map);
96+
assertEquals("{\n" +
97+
" \"field1\": \"1\",\n" +
98+
" \"field2\": \"2\"\n" +
99+
"}", output);
100+
Config reflectionCfg = new Config.Builder()
101+
.indentionStep(2)
102+
.encodingMode(EncodingMode.REFLECTION_MODE)
103+
.build();
104+
output = JsonStream.serialize(reflectionCfg, map);
105+
assertEquals("{\n" +
106+
" \"field1\": \"1\",\n" +
107+
" \"field2\": \"2\"\n" +
108+
"}", output);
109+
}
110+
111+
public void test_indention_with_empty_map() {
112+
Config config = JsoniterSpi.getCurrentConfig().copyBuilder()
113+
.indentionStep(2)
114+
.encodingMode(EncodingMode.REFLECTION_MODE)
115+
.build();
116+
assertEquals("{}", JsonStream.serialize(config, new HashMap<String, String>()));
117+
config = JsoniterSpi.getCurrentConfig().copyBuilder()
118+
.indentionStep(2)
119+
.encodingMode(EncodingMode.DYNAMIC_MODE)
120+
.build();
121+
assertEquals("{}", JsonStream.serialize(config, new HashMap<String, String>()));
122+
}
83123
}

src/test/java/com/jsoniter/output/TestObject.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ public void test_indention() {
296296
.indentionStep(2)
297297
.encodingMode(EncodingMode.REFLECTION_MODE)
298298
.build();
299-
output = JsonStream.serialize(dynamicCfg, obj);
299+
output = JsonStream.serialize(reflectionCfg, obj);
300300
assertEquals("{\n" +
301301
" \"field1\": \"1\",\n" +
302302
" \"field2\": \"2\",\n" +

0 commit comments

Comments
 (0)