Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ src/test/java/org/tron/consensus2
src/main/java/META-INF/
src/main/resources/META-INF/
/bin/
bin/

# Eclipse IDE specific files and folders
/.project
Expand All @@ -57,3 +58,4 @@ Wallet

/framework/propPath
.cache
.claude
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ public void merge(ProgramTrace programTrace) {
this.ops.addAll(programTrace.ops);
}

public String asJsonString(boolean formatted) {
return serializeFieldsOnly(this, formatted);
public String asJsonString() {
return serializeFieldsOnly(this);
}

@Override
public String toString() {
return asJsonString(true);
return asJsonString();
}
}
67 changes: 11 additions & 56 deletions actuator/src/main/java/org/tron/core/vm/trace/Serializers.java
Original file line number Diff line number Diff line change
@@ -1,73 +1,28 @@
package org.tron.core.vm.trace;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
import java.io.IOException;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.encoders.Hex;
import org.tron.common.runtime.vm.DataWord;
import org.tron.core.vm.Op;

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

public static String serializeFieldsOnly(Object value, boolean pretty) {
try {
ObjectMapper mapper = createMapper(pretty);
mapper.setVisibilityChecker(fieldsOnlyVisibilityChecker(mapper));
private static final ObjectMapper mapper = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.visibility(PropertyAccessor.FIELD, Visibility.ANY)
.visibility(PropertyAccessor.GETTER, Visibility.NONE)
.visibility(PropertyAccessor.IS_GETTER, Visibility.NONE)
.build();

public static String serializeFieldsOnly(Object value) {
try {
return mapper.writeValueAsString(value);
} catch (Exception e) {
logger.error("JSON serialization error: ", e);
return "{}";
}
}

private static VisibilityChecker<?> fieldsOnlyVisibilityChecker(ObjectMapper mapper) {
return mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE);
}

public static ObjectMapper createMapper(boolean pretty) {
ObjectMapper mapper = new ObjectMapper();
if (pretty) {
mapper.enable(SerializationFeature.INDENT_OUTPUT);
}
return mapper;
}

public static class DataWordSerializer extends JsonSerializer<DataWord> {

@Override
public void serialize(DataWord energy, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeString(energy.value().toString());
}
}

public static class ByteArraySerializer extends JsonSerializer<byte[]> {

@Override
public void serialize(byte[] memory, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeString(Hex.toHexString(memory));
}
}

public static class OpCodeSerializer extends JsonSerializer<Byte> {

@Override
public void serialize(Byte op, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeString(Op.getNameOf(op));
}
}
}
2 changes: 1 addition & 1 deletion common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ sourceCompatibility = 1.8


dependencies {
api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.3' // https://github.com/FasterXML/jackson-databind/issues/3627
api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.6' // https://github.com/FasterXML/jackson-databind/issues/3627
api "com.cedarsoftware:java-util:3.2.0"
api group: 'org.apache.httpcomponents', name: 'httpasyncclient', version: '4.1.1'
api group: 'commons-codec', name: 'commons-codec', version: '1.11'
Expand Down
5 changes: 3 additions & 2 deletions common/src/main/java/org/tron/common/utils/JsonUtil.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package org.tron.common.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import org.springframework.util.StringUtils;

public class JsonUtil {

private static final ObjectMapper om = JsonMapper.builder().build();

public static final <T> T json2Obj(String jsonString, Class<T> clazz) {
if (!StringUtils.isEmpty(jsonString) && clazz != null) {
try {
ObjectMapper om = new ObjectMapper();
return om.readValue(jsonString, clazz);
} catch (Exception var3) {
throw new RuntimeException(var3);
Expand All @@ -22,7 +24,6 @@ public static final String obj2Json(Object obj) {
if (obj == null) {
return null;
} else {
ObjectMapper om = new ObjectMapper();
try {
return om.writeValueAsString(obj);
} catch (Exception var3) {
Expand Down
168 changes: 168 additions & 0 deletions common/src/main/java/org/tron/json/JSON.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package org.tron.json;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
* Drop-in replacement for {@code com.alibaba.fastjson.JSON}.
* Swap the import line; no other source changes required for basic usages.
*
* <p>All static methods delegate to a shared, thread-safe Jackson {@link ObjectMapper} that is
* configured to match the lenient parsing behavior historically provided by Fastjson:
* <ul>
* <li>Unquoted field names and single-quoted strings are accepted.</li>
* <li>Unknown properties are ignored (Fastjson default).</li>
* <li>Floating-point numbers are mapped to {@link java.math.BigDecimal} for precision.</li>
* <li>Case-insensitive property matching is enabled.</li>
* </ul>
*/
public final class JSON {

/**
* Shared, fully-configured Jackson mapper. Exposed for callers that hold a mapper reference.
*/
public static final ObjectMapper MAPPER = JsonMapper.builder()
.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true)
.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.serializationInclusion(JsonInclude.Include.NON_NULL)
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
.build();

private JSON() {
}

// -------------------------------------------------------------------------
// parseObject
// -------------------------------------------------------------------------

/**
* Parses a JSON object string and returns a {@link JSONObject}.
* Mirrors {@code JSON.parseObject(String)} and {@code JSONObject.parseObject(String)}.
*/
public static JSONObject parseObject(String text) {
if (text == null || text.trim().isEmpty()) {
return null;
}
try {
JsonNode node = MAPPER.readTree(text);
if (node == null || node.isNull()) {
return null;
}
if (!node.isObject()) {
throw new JSONException("Expected JSON object but got: " + node.getNodeType());
}
return new JSONObject((ObjectNode) node);
} catch (JSONException e) {
throw e;
} catch (Exception e) {
throw new JSONException("Failed to parse JSON object: " + e.getMessage(), e);
}
}

/**
* Parses a JSON string and deserializes it into the given Java type.
* Mirrors {@code JSON.parseObject(String, Class)}.
*/
public static <T> T parseObject(String text, Class<T> clazz) {
if (text == null || text.isEmpty()) {
return null;
}
try {
return MAPPER.readValue(text, clazz);
} catch (Exception e) {
throw new JSONException("Failed to parse JSON object: " + e.getMessage(), e);
}
}

// -------------------------------------------------------------------------
// parse (validate / generic parse — callers typically ignore the return value)
// -------------------------------------------------------------------------

/**
* Parses any valid JSON value. Throws {@link JSONException} on invalid input
* so callers can detect malformed JSON (e.g. via try/catch), mirroring
* Fastjson's observable behaviour in this codebase.
* Mirrors {@code JSON.parse(String)}.
*/
public static JsonNode parse(String text) {
if (text == null || text.isEmpty()) {
return null;
}
try {
return MAPPER.readTree(text);
} catch (Exception e) {
throw new JSONException("Failed to parse JSON: " + e.getMessage(), e);
}
}

/**
* Parses a JSON array string and returns a {@link JSONArray}.
* Mirrors {@code JSON.parseArray(String)} and {@code JSONArray.parseArray(String)}.
*/
public static JSONArray parseArray(String text) {
return JSONArray.parseArray(text);
}

// -------------------------------------------------------------------------
// toJSONString
// -------------------------------------------------------------------------

/**
* Serializes an object to a compact JSON string.
* Mirrors {@code JSON.toJSONString(Object)}.
*/
public static String toJSONString(Object obj) {
if (obj == null) {
return "null";
}
// Unwrap our own wrapper types so the inner Jackson node is serialized
if (obj instanceof JSONObject) {
return ((JSONObject) obj).unwrap().toString();
}
if (obj instanceof JSONArray) {
return ((JSONArray) obj).unwrap().toString();
}
try {
return MAPPER.writeValueAsString(obj);
} catch (Exception e) {
throw new JSONException("Failed to serialise object: " + e.getMessage(), e);
}
}

/**
* Serializes an object to a JSON string, optionally pretty-printed.
* Mirrors {@code JSON.toJSONString(Object, boolean)}.
*/
public static String toJSONString(Object obj, boolean prettyFormat) {
if (!prettyFormat) {
return toJSONString(obj);
}
if (obj == null) {
return "null";
}
try {
if (obj instanceof JSONObject) {
return MAPPER.writerWithDefaultPrettyPrinter()
.writeValueAsString(((JSONObject) obj).unwrap());
}
if (obj instanceof JSONArray) {
return MAPPER.writerWithDefaultPrettyPrinter()
.writeValueAsString(((JSONArray) obj).unwrap());
}
return MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (Exception e) {
throw new JSONException("Failed to serialise object: " + e.getMessage(), e);
}
}
}
Loading
Loading