Skip to content

Commit 9a5d983

Browse files
committed
#81 support indention in dynamic codegen, part 1: object
1 parent 7ddb55c commit 9a5d983

File tree

5 files changed

+146
-63
lines changed

5 files changed

+146
-63
lines changed

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public static CodegenResult genArray(String cacheKey, ClassInfo classInfo) {
3030
if (isCollectionValueNullable) {
3131
ctx.append("if (e == null) { stream.writeNull(); } else {");
3232
CodegenImplNative.genWriteOp(ctx, "e", compType, true);
33-
ctx.append("}");
33+
ctx.append("}"); // if
3434
} else {
3535
CodegenImplNative.genWriteOp(ctx, "e", compType, false);
3636
}
@@ -40,13 +40,13 @@ public static CodegenResult genArray(String cacheKey, ClassInfo classInfo) {
4040
if (isCollectionValueNullable) {
4141
ctx.append("if (e == null) { stream.writeNull(); } else {");
4242
CodegenImplNative.genWriteOp(ctx, "e", compType, true);
43-
ctx.append("}");
43+
ctx.append("}"); // if
4444
} else {
4545
CodegenImplNative.genWriteOp(ctx, "e", compType, false);
4646
}
47-
ctx.append("}");
47+
ctx.append("}"); // while
4848
ctx.buffer(']');
49-
ctx.append("}");
49+
ctx.append("}"); // public static void encode_
5050
return ctx;
5151
}
5252

@@ -100,13 +100,13 @@ private static CodegenResult genList(String cacheKey, Class clazz, Type compType
100100
if (isCollectionValueNullable) {
101101
ctx.append("if (e == null) { stream.writeNull(); } else {");
102102
CodegenImplNative.genWriteOp(ctx, "e", compType, true);
103-
ctx.append("}");
103+
ctx.append("}"); // if
104104
} else {
105105
CodegenImplNative.genWriteOp(ctx, "e", compType, false);
106106
}
107-
ctx.append("}");
107+
ctx.append("}"); // for
108108
ctx.buffer(']');
109-
ctx.append("}");
109+
ctx.append("}"); // public static void encode_
110110
return ctx;
111111
}
112112

@@ -124,7 +124,7 @@ private static CodegenResult genCollection(String cacheKey, Class clazz, Type co
124124
if (isCollectionValueNullable) {
125125
ctx.append("if (e == null) { stream.writeNull(); } else {");
126126
CodegenImplNative.genWriteOp(ctx, "e", compType, true);
127-
ctx.append("}");
127+
ctx.append("}"); // if
128128
} else {
129129
CodegenImplNative.genWriteOp(ctx, "e", compType, false);
130130
}
@@ -134,13 +134,13 @@ private static CodegenResult genCollection(String cacheKey, Class clazz, Type co
134134
if (isCollectionValueNullable) {
135135
ctx.append("if (e == null) { stream.writeNull(); } else {");
136136
CodegenImplNative.genWriteOp(ctx, "e", compType, true);
137-
ctx.append("}");
137+
ctx.append("}"); // if
138138
} else {
139139
CodegenImplNative.genWriteOp(ctx, "e", compType, false);
140140
}
141-
ctx.append("}");
141+
ctx.append("}"); // while
142142
ctx.buffer(']');
143-
ctx.append("}");
143+
ctx.append("}"); // public static void encode_
144144
return ctx;
145145
}
146146

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,9 +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;
272273
String cacheKey = TypeLiteral.create(valueType).getEncoderCacheKey();
273274
if (JsoniterSpi.getEncoder(cacheKey) == null) {
274-
if (!isNullable && String.class == valueType) {
275+
if (supportBuffer && !isNullable && String.class == valueType) {
275276
ctx.buffer('"');
276277
ctx.append(String.format("com.jsoniter.output.CodegenAccess.writeStringWithoutQuote((java.lang.String)%s, stream);", code));
277278
ctx.buffer('"');

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

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

77
class CodegenImplObject {
88
public static CodegenResult genObject(ClassInfo classInfo) {
9-
9+
boolean supportBuffer = 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-
ctx.buffer('{');
16+
if (supportBuffer) {
17+
ctx.buffer('{');
18+
} else {
19+
ctx.append("stream.writeObjectStart();");
20+
}
1721
for (EncodeTo encodeTo : encodeTos) {
1822
notFirst = genField(ctx, encodeTo.binding, encodeTo.toName, notFirst);
1923
}
@@ -34,7 +38,11 @@ public static CodegenResult genObject(ClassInfo classInfo) {
3438
ctx.append(String.format("obj.%s(stream);", unwrapper.method.getName()));
3539
}
3640
}
37-
ctx.buffer('}');
41+
if (supportBuffer) {
42+
ctx.buffer('}');
43+
} else {
44+
ctx.append("stream.writeObjectEnd();");
45+
}
3846
} else {
3947
ctx.buffer("{}");
4048
}
@@ -51,6 +59,7 @@ private static boolean hasFieldOutput(ClassDescriptor desc) {
5159
}
5260

5361
private static int genField(CodegenResult ctx, Binding binding, String toName, int notFirst) {
62+
boolean supportBuffer = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
5463
String fieldCacheKey = binding.encoderCacheKey();
5564
Encoder encoder = JsoniterSpi.getEncoder(fieldCacheKey);
5665
boolean isCollectionValueNullable = binding.isCollectionValueNullable;
@@ -78,21 +87,33 @@ private static int genField(CodegenResult ctx, Binding binding, String toName, i
7887
}
7988
ctx.append(String.format("if (%s != null) {", valueAccessor));
8089
notFirst = appendComma(ctx, notFirst);
81-
ctx.append(CodegenResult.bufferToWriteOp("\"" + toName + "\":"));
90+
if (supportBuffer) {
91+
ctx.append(CodegenResult.bufferToWriteOp("\"" + toName + "\":"));
92+
} else {
93+
ctx.append(String.format("stream.writeObjectField(\"%s\");", toName));
94+
}
8295
} else {
8396
notFirst = appendComma(ctx, notFirst);
97+
if (supportBuffer) {
98+
ctx.buffer('"');
99+
ctx.buffer(toName);
100+
ctx.buffer('"');
101+
ctx.buffer(':');
102+
} else {
103+
ctx.append(String.format("stream.writeObjectField(\"%s\");", toName));
104+
}
105+
ctx.append(String.format("if (%s == null) { stream.writeNull(); } else {", valueAccessor));
106+
}
107+
} else {
108+
notFirst = appendComma(ctx, notFirst);
109+
if (supportBuffer) {
84110
ctx.buffer('"');
85111
ctx.buffer(toName);
86112
ctx.buffer('"');
87113
ctx.buffer(':');
88-
ctx.append(String.format("if (%s == null) { stream.writeNull(); } else {", valueAccessor));
114+
} else {
115+
ctx.append(String.format("stream.writeObjectField(\"%s\");", toName));
89116
}
90-
} else {
91-
notFirst = appendComma(ctx, notFirst);
92-
ctx.buffer('"');
93-
ctx.buffer(toName);
94-
ctx.buffer('"');
95-
ctx.buffer(':');
96117
}
97118
if (encoder == null) {
98119
CodegenImplNative.genWriteOp(ctx, valueAccessor, binding.valueType, nullable, isCollectionValueNullable);
@@ -107,10 +128,19 @@ private static int genField(CodegenResult ctx, Binding binding, String toName, i
107128
}
108129

109130
private static int appendComma(CodegenResult ctx, int notFirst) {
131+
boolean supportBuffer = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
110132
if (notFirst == 1) { // definitely not first
111-
ctx.buffer(',');
133+
if (supportBuffer) {
134+
ctx.buffer(',');
135+
} else {
136+
ctx.append("stream.writeMore();");
137+
}
112138
} else if (notFirst == 2) { // maybe not first, previous field is omitNull
113-
ctx.append("if (notFirst) { stream.write(','); } else { notFirst = true; }");
139+
if (supportBuffer) {
140+
ctx.append("if (notFirst) { stream.write(','); } else { notFirst = true; }");
141+
} else {
142+
ctx.append("if (notFirst) { stream.writeMore(); } else { notFirst = true; }");
143+
}
114144
} else { // this is the first, do not write comma
115145
notFirst = 1;
116146
}

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

Lines changed: 55 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,18 @@
11
package com.jsoniter.output;
22

3+
import com.jsoniter.spi.JsonException;
4+
import com.jsoniter.spi.JsoniterSpi;
5+
36
class CodegenResult {
47

8+
private final boolean supportBuffer;
59
String prelude = null; // first
610
String epilogue = null; // last
711
private StringBuilder lines = new StringBuilder();
812
private StringBuilder buffered = new StringBuilder();
913

10-
public static String bufferToWriteOp(String buffered) {
11-
if (buffered == null) {
12-
return "";
13-
}
14-
if (buffered.length() == 1) {
15-
return String.format("stream.write((byte)'%s');", escape(buffered.charAt(0)));
16-
} else if (buffered.length() == 2) {
17-
return String.format("stream.write((byte)'%s', (byte)'%s');",
18-
escape(buffered.charAt(0)), escape(buffered.charAt(1)));
19-
} else if (buffered.length() == 3) {
20-
return String.format("stream.write((byte)'%s', (byte)'%s', (byte)'%s');",
21-
escape(buffered.charAt(0)), escape(buffered.charAt(1)), escape(buffered.charAt(2)));
22-
} else if (buffered.length() == 4) {
23-
return String.format("stream.write((byte)'%s', (byte)'%s', (byte)'%s', (byte)'%s');",
24-
escape(buffered.charAt(0)), escape(buffered.charAt(1)), escape(buffered.charAt(2)), escape(buffered.charAt(3)));
25-
} else {
26-
StringBuilder escaped = new StringBuilder();
27-
for (int i = 0; i < buffered.length(); i++) {
28-
char c = buffered.charAt(i);
29-
if (c == '"') {
30-
escaped.append('\\');
31-
}
32-
escaped.append(c);
33-
}
34-
return String.format("stream.writeRaw(\"%s\", %s);", escaped.toString(), buffered.length());
35-
}
36-
}
37-
38-
private static String escape(char c) {
39-
if (c == '"') {
40-
return "\\\"";
41-
}
42-
if (c == '\\') {
43-
return "\\\\";
44-
}
45-
return String.valueOf(c);
14+
public CodegenResult() {
15+
supportBuffer = JsoniterSpi.getCurrentConfig().indentionStep() == 0;
4616
}
4717

4818
public void append(String str) {
@@ -56,14 +26,23 @@ public void append(String str) {
5626
}
5727

5828
public void buffer(char c) {
59-
buffered.append(c);
29+
if (supportBuffer) {
30+
buffered.append(c);
31+
} else {
32+
throw new UnsupportedOperationException("internal error: should not call buffer when indention step > 0");
33+
}
6034
}
6135

6236
public void buffer(String s) {
6337
if (s == null) {
6438
return;
6539
}
66-
buffered.append(s);
40+
if (supportBuffer) {
41+
buffered.append(s);
42+
} else {
43+
throw new UnsupportedOperationException("internal error: should not call buffer when indention step > 0");
44+
45+
}
6746
}
6847

6948
public void flushBuffer() {
@@ -111,4 +90,42 @@ private static void append(StringBuilder lines, String line) {
11190
lines.append(line);
11291
lines.append('\n');
11392
}
93+
94+
public static String bufferToWriteOp(String buffered) {
95+
if (buffered == null) {
96+
return "";
97+
}
98+
if (buffered.length() == 1) {
99+
return String.format("stream.write((byte)'%s');", escape(buffered.charAt(0)));
100+
} else if (buffered.length() == 2) {
101+
return String.format("stream.write((byte)'%s', (byte)'%s');",
102+
escape(buffered.charAt(0)), escape(buffered.charAt(1)));
103+
} else if (buffered.length() == 3) {
104+
return String.format("stream.write((byte)'%s', (byte)'%s', (byte)'%s');",
105+
escape(buffered.charAt(0)), escape(buffered.charAt(1)), escape(buffered.charAt(2)));
106+
} else if (buffered.length() == 4) {
107+
return String.format("stream.write((byte)'%s', (byte)'%s', (byte)'%s', (byte)'%s');",
108+
escape(buffered.charAt(0)), escape(buffered.charAt(1)), escape(buffered.charAt(2)), escape(buffered.charAt(3)));
109+
} else {
110+
StringBuilder escaped = new StringBuilder();
111+
for (int i = 0; i < buffered.length(); i++) {
112+
char c = buffered.charAt(i);
113+
if (c == '"') {
114+
escaped.append('\\');
115+
}
116+
escaped.append(c);
117+
}
118+
return String.format("stream.writeRaw(\"%s\", %s);", escaped.toString(), buffered.length());
119+
}
120+
}
121+
122+
private static String escape(char c) {
123+
if (c == '"') {
124+
return "\\\"";
125+
}
126+
if (c == '\\') {
127+
return "\\\\";
128+
}
129+
return String.valueOf(c);
130+
}
114131
}

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,39 @@ public void test_private_class() {
268268

269269
}
270270
}
271+
272+
public static class TestObject14 {
273+
@JsonProperty(nullable = true, omitNull = true)
274+
public String field1;
275+
@JsonProperty(nullable = false)
276+
public String field2;
277+
@JsonProperty(nullable = true, omitNull = false)
278+
public String field3;
279+
}
280+
281+
public void test_indention() {
282+
Config dynamicCfg = new Config.Builder()
283+
.indentionStep(2)
284+
.encodingMode(EncodingMode.DYNAMIC_MODE)
285+
.build();
286+
TestObject14 obj = new TestObject14();
287+
obj.field1 = "1";
288+
obj.field2 = "2";
289+
String output = JsonStream.serialize(dynamicCfg, obj);
290+
assertEquals("{\n" +
291+
" \"field1\": \"1\",\n" +
292+
" \"field2\": \"2\",\n" +
293+
" \"field3\": null\n" +
294+
"}", output);
295+
Config reflectionCfg = new Config.Builder()
296+
.indentionStep(2)
297+
.encodingMode(EncodingMode.REFLECTION_MODE)
298+
.build();
299+
output = JsonStream.serialize(dynamicCfg, obj);
300+
assertEquals("{\n" +
301+
" \"field1\": \"1\",\n" +
302+
" \"field2\": \"2\",\n" +
303+
" \"field3\": null\n" +
304+
"}", output);
305+
}
271306
}

0 commit comments

Comments
 (0)