Skip to content

Commit a1417f1

Browse files
committed
refactor(framework): replace fastjson with jackson
Remove the fastjson and replace it with Jackson-backed drop-in wrappers (JSON, JSONObject, JSONArray,JSONException). Motivation: - Fastjson has a history of critical CVEs and is no longer actively maintained for 1.x - Jackson-databind 2.18.6 addresses CVE GHSA-72hv-8253-57qq Core changes (common module): - Add org.tron.json.{JSON, JSONObject, JSONArray, JSONException} wrappers backed by a shared Jackson ObjectMapper configured to match Fastjson 1.x parsing/serialization. - Upgrade jackson-databind 2.18.3 → 2.18.6 HTTP servlet changes (framework module): - Swap import from com.alibaba.fastjson → org.tron.json across all HTTP API servlets, JSON-RPC layer, and event/log parsers Test changes: - Add BaseHttpTest base class managing Args lifecycle, Wallet mock, MINIMAL_TX constant, and request/response factory methods (postRequest, getRequest, newResponse) Build: - Remove fastjson from common/build.gradle dependencies - Update gradle/verification-metadata.xml for jackson 2.18.6
1 parent 208807d commit a1417f1

167 files changed

Lines changed: 3980 additions & 273 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ src/test/java/org/tron/consensus2
3636
src/main/java/META-INF/
3737
src/main/resources/META-INF/
3838
/bin/
39+
bin/
3940

4041
# Eclipse IDE specific files and folders
4142
/.project
@@ -57,3 +58,4 @@ Wallet
5758

5859
/framework/propPath
5960
.cache
61+
.claude

actuator/src/main/java/org/tron/core/vm/trace/ProgramTrace.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,12 @@ public void merge(ProgramTrace programTrace) {
9090
this.ops.addAll(programTrace.ops);
9191
}
9292

93-
public String asJsonString(boolean formatted) {
94-
return serializeFieldsOnly(this, formatted);
93+
public String asJsonString() {
94+
return serializeFieldsOnly(this);
9595
}
9696

9797
@Override
9898
public String toString() {
99-
return asJsonString(true);
99+
return asJsonString();
100100
}
101101
}
Lines changed: 11 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,28 @@
11
package org.tron.core.vm.trace;
22

3-
import com.fasterxml.jackson.annotation.JsonAutoDetect;
4-
import com.fasterxml.jackson.core.JsonGenerator;
5-
import com.fasterxml.jackson.core.JsonProcessingException;
6-
import com.fasterxml.jackson.databind.JsonSerializer;
3+
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
4+
import com.fasterxml.jackson.annotation.PropertyAccessor;
75
import com.fasterxml.jackson.databind.ObjectMapper;
86
import com.fasterxml.jackson.databind.SerializationFeature;
9-
import com.fasterxml.jackson.databind.SerializerProvider;
10-
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
11-
import java.io.IOException;
7+
import com.fasterxml.jackson.databind.json.JsonMapper;
128
import lombok.extern.slf4j.Slf4j;
13-
import org.bouncycastle.util.encoders.Hex;
14-
import org.tron.common.runtime.vm.DataWord;
15-
import org.tron.core.vm.Op;
169

1710
@Slf4j(topic = "VM")
1811
public final class Serializers {
1912

20-
public static String serializeFieldsOnly(Object value, boolean pretty) {
21-
try {
22-
ObjectMapper mapper = createMapper(pretty);
23-
mapper.setVisibilityChecker(fieldsOnlyVisibilityChecker(mapper));
13+
private static final ObjectMapper mapper = JsonMapper.builder()
14+
.enable(SerializationFeature.INDENT_OUTPUT)
15+
.visibility(PropertyAccessor.FIELD, Visibility.ANY)
16+
.visibility(PropertyAccessor.GETTER, Visibility.NONE)
17+
.visibility(PropertyAccessor.IS_GETTER, Visibility.NONE)
18+
.build();
2419

20+
public static String serializeFieldsOnly(Object value) {
21+
try {
2522
return mapper.writeValueAsString(value);
2623
} catch (Exception e) {
2724
logger.error("JSON serialization error: ", e);
2825
return "{}";
2926
}
3027
}
31-
32-
private static VisibilityChecker<?> fieldsOnlyVisibilityChecker(ObjectMapper mapper) {
33-
return mapper.getSerializationConfig().getDefaultVisibilityChecker()
34-
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
35-
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
36-
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE);
37-
}
38-
39-
public static ObjectMapper createMapper(boolean pretty) {
40-
ObjectMapper mapper = new ObjectMapper();
41-
if (pretty) {
42-
mapper.enable(SerializationFeature.INDENT_OUTPUT);
43-
}
44-
return mapper;
45-
}
46-
47-
public static class DataWordSerializer extends JsonSerializer<DataWord> {
48-
49-
@Override
50-
public void serialize(DataWord energy, JsonGenerator jgen, SerializerProvider provider)
51-
throws IOException, JsonProcessingException {
52-
jgen.writeString(energy.value().toString());
53-
}
54-
}
55-
56-
public static class ByteArraySerializer extends JsonSerializer<byte[]> {
57-
58-
@Override
59-
public void serialize(byte[] memory, JsonGenerator jgen, SerializerProvider provider)
60-
throws IOException, JsonProcessingException {
61-
jgen.writeString(Hex.toHexString(memory));
62-
}
63-
}
64-
65-
public static class OpCodeSerializer extends JsonSerializer<Byte> {
66-
67-
@Override
68-
public void serialize(Byte op, JsonGenerator jgen, SerializerProvider provider)
69-
throws IOException, JsonProcessingException {
70-
jgen.writeString(Op.getNameOf(op));
71-
}
72-
}
7328
}

common/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ sourceCompatibility = 1.8
88

99

1010
dependencies {
11-
api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.3' // https://github.com/FasterXML/jackson-databind/issues/3627
11+
api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.6' // https://github.com/FasterXML/jackson-databind/issues/3627
1212
api "com.cedarsoftware:java-util:3.2.0"
1313
api group: 'org.apache.httpcomponents', name: 'httpasyncclient', version: '4.1.1'
1414
api group: 'commons-codec', name: 'commons-codec', version: '1.11'

common/src/main/java/org/tron/common/utils/JsonUtil.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
package org.tron.common.utils;
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.fasterxml.jackson.databind.json.JsonMapper;
45
import org.springframework.util.StringUtils;
56

67
public class JsonUtil {
78

9+
private static final ObjectMapper om = new JsonMapper();
10+
811
public static final <T> T json2Obj(String jsonString, Class<T> clazz) {
912
if (!StringUtils.isEmpty(jsonString) && clazz != null) {
1013
try {
11-
ObjectMapper om = new ObjectMapper();
1214
return om.readValue(jsonString, clazz);
1315
} catch (Exception var3) {
1416
throw new RuntimeException(var3);
@@ -22,7 +24,6 @@ public static final String obj2Json(Object obj) {
2224
if (obj == null) {
2325
return null;
2426
} else {
25-
ObjectMapper om = new ObjectMapper();
2627
try {
2728
return om.writeValueAsString(obj);
2829
} catch (Exception var3) {
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package org.tron.json;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import com.fasterxml.jackson.core.json.JsonReadFeature;
5+
import com.fasterxml.jackson.databind.DeserializationFeature;
6+
import com.fasterxml.jackson.databind.JsonNode;
7+
import com.fasterxml.jackson.databind.MapperFeature;
8+
import com.fasterxml.jackson.databind.ObjectMapper;
9+
import com.fasterxml.jackson.databind.SerializationFeature;
10+
import com.fasterxml.jackson.databind.json.JsonMapper;
11+
import com.fasterxml.jackson.databind.node.ObjectNode;
12+
13+
/**
14+
* Drop-in replacement for {@code com.alibaba.fastjson.JSON}.
15+
*/
16+
public final class JSON {
17+
18+
public static final ObjectMapper MAPPER = JsonMapper.builder()
19+
// Fastjson Feature.AllowUnQuotedFieldNames (default ON)
20+
.enable(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES)
21+
// Fastjson Feature.AllowSingleQuotes (default ON)
22+
.enable(JsonReadFeature.ALLOW_SINGLE_QUOTES)
23+
// Fastjson tolerates trailing commas (e.g. {"a":1,}) by default
24+
.enable(JsonReadFeature.ALLOW_TRAILING_COMMA)
25+
// Fastjson accepts NaN/Infinity as valid tokens
26+
.enable(JsonReadFeature.ALLOW_NON_NUMERIC_NUMBERS)
27+
// Fastjson accepts leading plus sign for numbers (e.g. +123)
28+
.enable(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS)
29+
// Fastjson accepts leading decimal point for numbers (e.g. .5)
30+
.enable(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS)
31+
// Fastjson accepts trailing decimal point for numbers (e.g. 5.)
32+
.enable(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)
33+
// Fastjson accepts leading zeros for numbers (e.g. 007)
34+
.enable(JsonReadFeature.ALLOW_LEADING_ZEROS_FOR_NUMBERS)
35+
// Fastjson accepts unescaped control chars in strings (e.g. raw tab/newline)
36+
.enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS)
37+
// Fastjson accepts backslash-escaping any character (e.g. \q → q)
38+
.enable(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER)
39+
// Fastjson accepts Java-style comments (// and /* */)
40+
.enable(JsonReadFeature.ALLOW_JAVA_COMMENTS)
41+
// Fastjson Feature.UseBigDecimal (default ON)
42+
// https://github.com/alibaba/fastjson/wiki/deserialize_disable_bigdecimal_cn
43+
.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true)
44+
// Fastjson Feature.IgnoreNotMatch (default ON) — unknown fields silently ignored
45+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
46+
// Fastjson serializes empty beans as "{}" without error
47+
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
48+
// Fastjson omits null-valued fields by default (WriteMapNullValue is OFF by default)
49+
// https://github.com/alibaba/fastjson/wiki/WriteNull_cn
50+
.serializationInclusion(JsonInclude.Include.NON_NULL)
51+
// Fastjson uses WriteDateUseDateFormat (string) not timestamps by default
52+
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
53+
// Fastjson smart-match: field names are matched ignoring case/underscores by default
54+
// (DisableFieldSmartMatch is OFF by default → smart match ON)
55+
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
56+
.build();
57+
58+
private JSON() {
59+
}
60+
61+
/**
62+
* Returns {@code true} when {@code text} is null, blank, or a
63+
* case-insensitive {@code "null"} literal — mirroring Fastjson's lenient
64+
* treatment of these inputs as JSON {@code null}.
65+
*/
66+
static boolean isNullLiteral(String text) {
67+
if (text == null) {
68+
return true;
69+
}
70+
String trimmed = text.trim();
71+
return trimmed.isEmpty() || "null".equalsIgnoreCase(trimmed);
72+
}
73+
74+
public static JSONObject parseObject(String text) {
75+
if (isNullLiteral(text)) {
76+
return null;
77+
}
78+
try {
79+
JsonNode node = MAPPER.readTree(text);
80+
if (node == null || node.isNull()) {
81+
return null;
82+
}
83+
if (!node.isObject()) {
84+
throw new JSONException("can not cast to JSONObject.");
85+
}
86+
return new JSONObject((ObjectNode) node);
87+
} catch (JSONException e) {
88+
throw e;
89+
} catch (Exception e) {
90+
throw new JSONException(e.getMessage(), e);
91+
}
92+
}
93+
94+
public static <T> T parseObject(String text, Class<T> clazz) {
95+
if (isNullLiteral(text)) {
96+
return null;
97+
}
98+
if (clazz == JSONObject.class) {
99+
return clazz.cast(parseObject(text));
100+
}
101+
if (clazz == JSONArray.class) {
102+
return clazz.cast(parseArray(text));
103+
}
104+
try {
105+
return MAPPER.readValue(text, clazz);
106+
} catch (Exception e) {
107+
throw new JSONException(e.getMessage(), e);
108+
}
109+
}
110+
111+
public static JsonNode parse(String text) {
112+
if (isNullLiteral(text)) {
113+
return null;
114+
}
115+
try {
116+
JsonNode node = MAPPER.readTree(text);
117+
if (node == null || node.isNull()) {
118+
return null;
119+
}
120+
return node;
121+
} catch (Exception e) {
122+
throw new JSONException(e.getMessage(), e);
123+
}
124+
}
125+
126+
static JSONArray parseArray(String text) {
127+
return JSONArray.parseArray(text);
128+
}
129+
130+
public static String toJSONString(Object obj) {
131+
return toJSONString(obj, false);
132+
}
133+
134+
public static String toJSONString(Object obj, boolean pretty) {
135+
if (obj == null) {
136+
return "null";
137+
}
138+
try {
139+
if (obj instanceof JSONObject) {
140+
return pretty ? MAPPER.writerWithDefaultPrettyPrinter()
141+
.writeValueAsString(((JSONObject) obj).unwrap())
142+
: MAPPER.writeValueAsString(((JSONObject) obj).unwrap());
143+
}
144+
if (obj instanceof JSONArray) {
145+
return pretty ? MAPPER.writerWithDefaultPrettyPrinter()
146+
.writeValueAsString(((JSONArray) obj).unwrap())
147+
: MAPPER.writeValueAsString(((JSONArray) obj).unwrap());
148+
}
149+
return pretty ? MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj)
150+
: MAPPER.writeValueAsString(obj);
151+
} catch (Exception e) {
152+
throw new JSONException(e.getMessage(), e);
153+
}
154+
}
155+
}

0 commit comments

Comments
 (0)