Skip to content

Commit 16b15bd

Browse files
committed
fix(json): align jackson parser with fastjson defaults
1 parent afb38e7 commit 16b15bd

3 files changed

Lines changed: 23 additions & 48 deletions

File tree

common/src/main/java/org/tron/json/JSON.java

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import com.fasterxml.jackson.core.json.JsonReadFeature;
77
import com.fasterxml.jackson.databind.DeserializationFeature;
88
import com.fasterxml.jackson.databind.JsonNode;
9-
import com.fasterxml.jackson.databind.MapperFeature;
109
import com.fasterxml.jackson.databind.ObjectMapper;
1110
import com.fasterxml.jackson.databind.SerializationFeature;
1211
import com.fasterxml.jackson.databind.json.JsonMapper;
@@ -41,22 +40,27 @@ public final class JSON {
4140
.enable(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES)
4241
// Fastjson Feature.AllowSingleQuotes (default ON)
4342
.enable(JsonReadFeature.ALLOW_SINGLE_QUOTES)
44-
// Fastjson tolerates trailing commas (e.g. {"a":1,}) by default
43+
// Partial compatibility with Fastjson Feature.AllowArbitraryCommas:
44+
// this only covers a single trailing comma like {"a":1,} or [1,2,].
45+
// Fastjson also accepts repeated/arbitrary commas like {"a":1,,,,} and
46+
// [1,,2], which Jackson does not support with this feature.
4547
.enable(JsonReadFeature.ALLOW_TRAILING_COMMA)
46-
// Fastjson accepts NaN as valid tokens, Infinity is invalid
48+
// Fastjson accepts NaN as null but rejects Infinity by default.
49+
// Jackson enables both with this feature, so every parse path must normalize
50+
// NaN and reject +/-Infinity after reading.
4751
.enable(JsonReadFeature.ALLOW_NON_NUMERIC_NUMBERS)
48-
// Fastjson accepts leading plus sign for numbers (e.g. +123)
52+
// Fastjson accepts a leading plus sign for numbers (for example +123, +0.5)
4953
.enable(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS)
50-
// Fastjson accepts leading decimal point for numbers (e.g. .5)
54+
// Partial compatibility for Fastjson's asymmetric decimal behavior:
55+
// Fastjson accepts +.5 but rejects .5 by default. Jackson cannot model only
56+
// the signed form, so enabling this also accepts .5.
5157
.enable(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS)
52-
// Fastjson accepts trailing decimal point for numbers (e.g. 5.)
58+
// Fastjson accepts a trailing decimal point for numbers (for example 5.)
5359
.enable(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)
54-
// Fastjson accepts leading zeros for numbers (e.g. 007)
60+
// Fastjson accepts leading zeros for numbers (for example 007)
5561
.enable(JsonReadFeature.ALLOW_LEADING_ZEROS_FOR_NUMBERS)
56-
// Fastjson accepts unescaped control chars in strings (e.g. raw tab/newline)
62+
// Fastjson accepts unescaped control chars in strings (for example raw tab/newline)
5763
.enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS)
58-
// Fastjson accepts backslash-escaping any character (e.g. \q -> q)
59-
.enable(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER)
6064
// Fastjson accepts Java-style comments (// and /* */)
6165
.enable(JsonReadFeature.ALLOW_JAVA_COMMENTS)
6266
// Fastjson Feature.UseBigDecimal (default ON)
@@ -69,11 +73,6 @@ public final class JSON {
6973
// Fastjson omits null-valued fields by default (WriteMapNullValue is OFF by default)
7074
// https://github.com/alibaba/fastjson/wiki/WriteNull_cn
7175
.serializationInclusion(JsonInclude.Include.NON_NULL)
72-
// Fastjson uses WriteDateUseDateFormat (string) not timestamps by default
73-
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
74-
// Fastjson smart-match: field names are matched ignoring case/underscores by default
75-
// (DisableFieldSmartMatch is OFF by default -> smart match ON)
76-
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
7776
.build();
7877

7978
private static JsonFactory buildFactory() {
@@ -230,23 +229,6 @@ public static JSONObject parseObject(String text) {
230229
}
231230
}
232231

233-
public static <T> T parseObject(String text, Class<T> clazz) {
234-
if (isNullLiteral(text)) {
235-
return null;
236-
}
237-
if (clazz == JSONObject.class) {
238-
return clazz.cast(parseObject(text));
239-
}
240-
if (clazz == JSONArray.class) {
241-
return clazz.cast(parseArray(text));
242-
}
243-
try {
244-
return MAPPER.readValue(text, clazz);
245-
} catch (Exception e) {
246-
throw new JSONException(e.getMessage(), e);
247-
}
248-
}
249-
250232
public static JsonNode parse(String text) {
251233
if (isNullLiteral(text)) {
252234
return null;

framework/src/test/java/org/tron/core/net/messagehandler/PbftDataSyncHandlerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.tron.core.net.messagehandler;
22

3+
import com.fasterxml.jackson.databind.ObjectMapper;
34
import com.google.protobuf.ByteString;
45
import java.lang.reflect.Field;
56
import java.util.ArrayList;
@@ -14,7 +15,6 @@
1415
import org.tron.core.db.PbftSignDataStore;
1516
import org.tron.core.net.message.pbft.PbftCommitMessage;
1617
import org.tron.core.store.DynamicPropertiesStore;
17-
import org.tron.json.JSON;
1818
import org.tron.protos.Protocol;
1919

2020
public class PbftDataSyncHandlerTest {
@@ -52,7 +52,7 @@ public void testProcessMessage() throws Exception {
5252
pbftDataSyncHandler.processPBFTCommitData(blockCapsule);
5353
Field field1 = PbftDataSyncHandler.class.getDeclaredField("pbftCommitMessageCache");
5454
field1.setAccessible(true);
55-
Map map = JSON.parseObject(JSON.toJSONString(field1.get(pbftDataSyncHandler)), Map.class);
55+
Map map = new ObjectMapper().convertValue(field1.get(pbftDataSyncHandler), Map.class);
5656
Assert.assertFalse(map.containsKey(0));
5757
}
5858
}

framework/src/test/java/org/tron/json/JsonTest.java

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.math.BigDecimal;
1313
import java.math.BigInteger;
1414
import java.util.Arrays;
15+
import java.util.Date;
1516
import java.util.List;
1617
import org.junit.Test;
1718

@@ -36,6 +37,8 @@ public void testTrailingComma() {
3637
assertEquals(3, array.size());
3738
assertEquals(2, array.get(1));
3839
assertEquals(1, ((JSONObject) array.get(2)).getIntValue("a"));
40+
assertThrows(JSONException.class, () -> JSON.parseObject("{c:'NULL',,,,,,}"));
41+
assertThrows(JSONException.class, () -> JSON.parseObject("[1,,2]"));
3942
}
4043

4144
@Test
@@ -68,7 +71,7 @@ public void testLeadingNumbers() {
6871
assertNotNull(o);
6972
assertEquals(1, o.getIntValue("a"));
7073
assertEquals(-2, o.getIntValue("b"));
71-
assertEquals("0.3", o.getBigDecimal("c").toPlainString()); // Fastjson will throw an error
74+
assertEquals("0.3", o.getBigDecimal("c").toPlainString());
7275
assertEquals("-0.4", o.getBigDecimal("d").toPlainString());
7376
assertEquals("0.5", o.getBigDecimal("e").toPlainString());
7477
assertEquals(6, o.getIntValue("f"));
@@ -87,9 +90,7 @@ public void testUnescapedControlChars() {
8790

8891
@Test
8992
public void testBackslashEscapeAnyChar() {
90-
JSONObject obj = JSON.parseObject("{\"a\":\"\\q\"}"); // Fastjson will throw an error
91-
assertNotNull(obj);
92-
assertEquals("q", obj.getString("a"));
93+
assertThrows(JSONException.class, () -> JSON.parseObject("{\"a\":\"\\q\"}"));
9394
}
9495

9596
@Test
@@ -151,21 +152,12 @@ public void testUppercaseNull() {
151152
}
152153

153154
@Test
154-
public void testParseToClass() {
155+
public void testParseHelpers() {
155156
assertNotNull(JSON.parse("{\"a\":1}"));
156157
assertEquals(1, JSON.parse("{\"a\":1}").get("a").intValue());
157158
assertNull(JSON.parse(null));
158159
assertNull(JSON.parse("null"));
159160

160-
// parseObject(text, Class) — JSONObject / JSONArray short-circuits
161-
assertEquals(1, JSON.parseObject("{\"a\":1}", JSONObject.class).getIntValue("a"));
162-
assertEquals(3, JSON.parseObject("[1,2,3]", JSONArray.class).size());
163-
164-
// parseObject(text, Class) — arbitrary POJO via Jackson
165-
Pojo p = JSON.parseObject("{\"name\":\"x\"}", Pojo.class);
166-
assertEquals("x", p.name);
167-
assertNull(JSON.parseObject(null, Pojo.class));
168-
169161
// JSONObject.parseObject delegate
170162
assertEquals(1, JSONObject.parseObject("{\"a\":1}").getIntValue("a"));
171163

@@ -180,6 +172,7 @@ public void testToJSONString() {
180172
assertEquals("{\"a\":1}", JSON.toJSONString(new JSONObject().put("a", 1)));
181173
assertEquals("[1,2]", JSON.toJSONString(JSON.parseArray("[1,2]")));
182174
assertEquals("\"hi\"", JSON.toJSONString("hi"));
175+
assertEquals("0", JSON.toJSONString(new Date(0)));
183176

184177
// pretty variant differs from compact for containers (exercises the pretty branch)
185178
JSONObject obj = new JSONObject().put("a", 1);

0 commit comments

Comments
 (0)