Skip to content

Commit 5e915bd

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 5e915bd

165 files changed

Lines changed: 3670 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: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package org.tron.json;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import com.fasterxml.jackson.core.JsonParser;
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+
.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
21+
// Fastjson Feature.AllowSingleQuotes (default ON)
22+
.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true)
23+
// Fastjson tolerates trailing commas (e.g. {"a":1,}) by default
24+
.configure(JsonParser.Feature.ALLOW_TRAILING_COMMA, true)
25+
// Fastjson Feature.UseBigDecimal (default ON)
26+
// https://github.com/alibaba/fastjson/wiki/deserialize_disable_bigdecimal_cn
27+
.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true)
28+
// Fastjson Feature.IgnoreNotMatch (default ON) — unknown fields silently ignored
29+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
30+
// Fastjson serializes empty beans as "{}" without error
31+
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
32+
// Fastjson omits null-valued fields by default (WriteMapNullValue is OFF by default)
33+
// https://github.com/alibaba/fastjson/wiki/WriteNull_cn
34+
.serializationInclusion(JsonInclude.Include.NON_NULL)
35+
// Fastjson uses WriteDateUseDateFormat (string) not timestamps by default
36+
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
37+
// Fastjson smart-match: field names are matched ignoring case/underscores by default
38+
// (DisableFieldSmartMatch is OFF by default → smart match ON)
39+
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
40+
.build();
41+
42+
private JSON() {
43+
}
44+
45+
/**
46+
* Returns {@code true} when {@code text} is null, blank, or a
47+
* case-insensitive {@code "null"} literal — mirroring Fastjson's lenient
48+
* treatment of these inputs as JSON {@code null}.
49+
*/
50+
static boolean isNullLiteral(String text) {
51+
if (text == null) {
52+
return true;
53+
}
54+
String trimmed = text.trim();
55+
return trimmed.isEmpty() || "null".equalsIgnoreCase(trimmed);
56+
}
57+
58+
public static JSONObject parseObject(String text) {
59+
if (isNullLiteral(text)) {
60+
return null;
61+
}
62+
try {
63+
JsonNode node = MAPPER.readTree(text);
64+
if (node == null || node.isNull()) {
65+
return null;
66+
}
67+
if (!node.isObject()) {
68+
throw new JSONException("can not cast to JSONObject.");
69+
}
70+
return new JSONObject((ObjectNode) node);
71+
} catch (JSONException e) {
72+
throw e;
73+
} catch (Exception e) {
74+
throw new JSONException(e.getMessage(), e);
75+
}
76+
}
77+
78+
public static <T> T parseObject(String text, Class<T> clazz) {
79+
if (isNullLiteral(text)) {
80+
return null;
81+
}
82+
if (clazz == JSONObject.class) {
83+
return clazz.cast(parseObject(text));
84+
}
85+
if (clazz == JSONArray.class) {
86+
return clazz.cast(parseArray(text));
87+
}
88+
try {
89+
return MAPPER.readValue(text, clazz);
90+
} catch (Exception e) {
91+
throw new JSONException(e.getMessage(), e);
92+
}
93+
}
94+
95+
public static JsonNode parse(String text) {
96+
if (isNullLiteral(text)) {
97+
return null;
98+
}
99+
try {
100+
JsonNode node = MAPPER.readTree(text);
101+
if (node == null || node.isNull()) {
102+
return null;
103+
}
104+
return node;
105+
} catch (Exception e) {
106+
throw new JSONException(e.getMessage(), e);
107+
}
108+
}
109+
110+
static JSONArray parseArray(String text) {
111+
return JSONArray.parseArray(text);
112+
}
113+
114+
public static String toJSONString(Object obj) {
115+
return toJSONString(obj, false);
116+
}
117+
118+
public static String toJSONString(Object obj, boolean pretty) {
119+
if (obj == null) {
120+
return "null";
121+
}
122+
try {
123+
if (obj instanceof JSONObject) {
124+
return pretty ? MAPPER.writerWithDefaultPrettyPrinter()
125+
.writeValueAsString(((JSONObject) obj).unwrap())
126+
: MAPPER.writeValueAsString(((JSONObject) obj).unwrap());
127+
}
128+
if (obj instanceof JSONArray) {
129+
return pretty ? MAPPER.writerWithDefaultPrettyPrinter()
130+
.writeValueAsString(((JSONArray) obj).unwrap())
131+
: MAPPER.writeValueAsString(((JSONArray) obj).unwrap());
132+
}
133+
return pretty ? MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj)
134+
: MAPPER.writeValueAsString(obj);
135+
} catch (Exception e) {
136+
throw new JSONException(e.getMessage(), e);
137+
}
138+
}
139+
}

0 commit comments

Comments
 (0)