Skip to content

Commit

Permalink
Support users to customize JsonUtil (apache#14508)
Browse files Browse the repository at this point in the history
  • Loading branch information
oxsean authored Sep 6, 2024
1 parent ca6909a commit 4a4d756
Show file tree
Hide file tree
Showing 31 changed files with 451 additions and 199 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@
*/
package org.apache.dubbo.common.json;

import org.apache.dubbo.common.extension.ExtensionScope;
import org.apache.dubbo.common.extension.SPI;

import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

@SPI
@SPI(scope = ExtensionScope.FRAMEWORK)
public interface JsonUtil {

String getName();

boolean isSupport();

boolean isJson(String json);
Expand All @@ -34,6 +38,8 @@ public interface JsonUtil {

String toJson(Object obj);

String toPrettyJson(Object obj);

List<?> getList(Map<String, ?> obj, String key);

List<Map<String, ?>> getListOfObjects(Map<String, ?> obj, String key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.Map;

public abstract class AbstractJsonUtilImpl implements JsonUtil {

@Override
public boolean isSupport() {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,56 @@
*/
package org.apache.dubbo.common.json.impl;

import org.apache.dubbo.common.extension.Activate;

import java.lang.reflect.Type;
import java.util.List;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONValidator;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.JSONWriter.Feature;
import com.alibaba.fastjson2.util.TypeUtils;

@Activate(order = 100, onClass = "com.alibaba.fastjson2.JSON")
public class FastJson2Impl extends AbstractJsonUtilImpl {

@Override
public String getName() {
return "fastjson2";
}

@Override
public boolean isJson(String json) {
JSONValidator validator = JSONValidator.from(json);
return validator.validate();
return JSONValidator.from(json).validate();
}

@Override
public <T> T toJavaObject(String json, Type type) {
return com.alibaba.fastjson2.JSON.parseObject(json, type);
return JSON.parseObject(json, type);
}

@Override
public <T> List<T> toJavaList(String json, Class<T> clazz) {
return com.alibaba.fastjson2.JSON.parseArray(json, clazz);
return JSON.parseArray(json, clazz);
}

@Override
public String toJson(Object obj) {
return com.alibaba.fastjson2.JSON.toJSONString(obj, JSONWriter.Feature.WriteEnumsUsingName);
return JSON.toJSONString(obj, Feature.WriteEnumsUsingName);
}

@Override
public String toPrettyJson(Object obj) {
return JSON.toJSONString(obj, Feature.WriteEnumsUsingName, Feature.PrettyFormat);
}

@Override
public Object convertObject(Object obj, Type type) {
return com.alibaba.fastjson2.util.TypeUtils.cast(obj, type);
return TypeUtils.cast(obj, type);
}

@Override
public Object convertObject(Object obj, Class<?> clazz) {
return com.alibaba.fastjson2.util.TypeUtils.cast(obj, clazz);
return TypeUtils.cast(obj, clazz);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,46 +16,64 @@
*/
package org.apache.dubbo.common.json.impl;

import org.apache.dubbo.common.extension.Activate;

import java.lang.reflect.Type;
import java.util.List;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.util.TypeUtils;

@Activate(order = 200, onClass = "com.alibaba.fastjson.JSON")
public class FastJsonImpl extends AbstractJsonUtilImpl {

@Override
public String getName() {
return "fastjson";
}

@Override
public boolean isJson(String json) {
try {
Object obj = com.alibaba.fastjson.JSON.parse(json);
return obj instanceof com.alibaba.fastjson.JSONObject || obj instanceof com.alibaba.fastjson.JSONArray;
} catch (com.alibaba.fastjson.JSONException e) {
Object obj = JSON.parse(json);
return obj instanceof JSONObject || obj instanceof JSONArray;
} catch (JSONException e) {
return false;
}
}

@Override
public <T> T toJavaObject(String json, Type type) {
return com.alibaba.fastjson.JSON.parseObject(json, type);
return JSON.parseObject(json, type);
}

@Override
public <T> List<T> toJavaList(String json, Class<T> clazz) {
return com.alibaba.fastjson.JSON.parseArray(json, clazz);
return JSON.parseArray(json, clazz);
}

@Override
public String toJson(Object obj) {
return com.alibaba.fastjson.JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);
return JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);
}

@Override
public String toPrettyJson(Object obj) {
return JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.PrettyFormat);
}

@Override
public Object convertObject(Object obj, Type type) {
return com.alibaba.fastjson.util.TypeUtils.cast(obj, type, ParserConfig.getGlobalInstance());
return TypeUtils.cast(obj, type, ParserConfig.getGlobalInstance());
}

@Override
public Object convertObject(Object obj, Class<?> clazz) {
return com.alibaba.fastjson.util.TypeUtils.cast(obj, clazz, ParserConfig.getGlobalInstance());
return TypeUtils.cast(obj, clazz, ParserConfig.getGlobalInstance());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,27 @@
*/
package org.apache.dubbo.common.json.impl;

import org.apache.dubbo.common.extension.Activate;

import java.lang.reflect.Type;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;

@Activate(order = 300, onClass = "com.google.gson.Gson")
public class GsonImpl extends AbstractJsonUtilImpl {
// weak reference of com.google.gson.Gson, prevent throw exception when init
private volatile Object gsonCache = null;

private volatile Gson gson;

@Override
public String getName() {
return "gson";
}

@Override
public boolean isJson(String json) {
Expand All @@ -46,15 +55,20 @@ public <T> T toJavaObject(String json, Type type) {

@Override
public <T> List<T> toJavaList(String json, Class<T> clazz) {
return getGson()
.fromJson(json, TypeToken.getParameterized(List.class, clazz).getType());
Type type = TypeToken.getParameterized(List.class, clazz).getType();
return getGson().fromJson(json, type);
}

@Override
public String toJson(Object obj) {
return getGson().toJson(obj);
}

@Override
public String toPrettyJson(Object obj) {
return createBuilder().setPrettyPrinting().create().toJson(obj);
}

@Override
public Object convertObject(Object obj, Type type) {
Gson gson = getGson();
Expand All @@ -67,14 +81,20 @@ public Object convertObject(Object obj, Class<?> clazz) {
return gson.fromJson(gson.toJsonTree(obj), clazz);
}

private Gson getGson() {
if (gsonCache == null || !(gsonCache instanceof Gson)) {
protected Gson getGson() {
Gson gson = this.gson;
if (gson == null) {
synchronized (this) {
if (gsonCache == null || !(gsonCache instanceof Gson)) {
gsonCache = new Gson();
gson = this.gson;
if (gson == null) {
this.gson = gson = createBuilder().create();
}
}
}
return (Gson) gsonCache;
return gson;
}

protected GsonBuilder createBuilder() {
return new GsonBuilder();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
package org.apache.dubbo.common.json.impl;

import org.apache.dubbo.common.extension.Activate;

import java.lang.reflect.Type;
import java.util.List;

Expand All @@ -24,19 +26,24 @@
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.json.JsonMapper;
import com.fasterxml.jackson.databind.json.JsonMapper.Builder;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

@Activate(order = 400, onClass = "com.fasterxml.jackson.databind.json.JsonMapper")
public class JacksonImpl extends AbstractJsonUtilImpl {
private final ObjectMapper objectMapper = new ObjectMapper();

private volatile Object jacksonCache = null;
private volatile JsonMapper mapper;

@Override
public String getName() {
return "jackson";
}

@Override
public boolean isJson(String json) {
try {
JsonNode node = objectMapper.readTree(json);
JsonNode node = getMapper().readTree(json);
return node.isObject() || node.isArray();
} catch (JsonProcessingException e) {
return false;
Expand All @@ -46,7 +53,8 @@ public boolean isJson(String json) {
@Override
public <T> T toJavaObject(String json, Type type) {
try {
return getJackson().readValue(json, getJackson().getTypeFactory().constructType(type));
JsonMapper mapper = getMapper();
return mapper.readValue(json, mapper.getTypeFactory().constructType(type));
} catch (com.fasterxml.jackson.core.JsonProcessingException e) {
throw new IllegalArgumentException(e);
}
Expand All @@ -55,8 +63,8 @@ public <T> T toJavaObject(String json, Type type) {
@Override
public <T> List<T> toJavaList(String json, Class<T> clazz) {
try {
return getJackson()
.readValue(json, getJackson().getTypeFactory().constructCollectionType(List.class, clazz));
JsonMapper mapper = getMapper();
return mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, clazz));
} catch (com.fasterxml.jackson.core.JsonProcessingException e) {
throw new IllegalArgumentException(e);
}
Expand All @@ -65,36 +73,50 @@ public <T> List<T> toJavaList(String json, Class<T> clazz) {
@Override
public String toJson(Object obj) {
try {
return getJackson().writeValueAsString(obj);
return getMapper().writeValueAsString(obj);
} catch (com.fasterxml.jackson.core.JsonProcessingException e) {
throw new IllegalArgumentException(e);
}
}

@Override
public String toPrettyJson(Object obj) {
try {
return getMapper().writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException(e);
}
}

@Override
public Object convertObject(Object obj, Type type) {
JsonMapper mapper = getJackson();
JsonMapper mapper = getMapper();
return mapper.convertValue(obj, mapper.constructType(type));
}

@Override
public Object convertObject(Object obj, Class<?> clazz) {
return getJackson().convertValue(obj, clazz);
return getMapper().convertValue(obj, clazz);
}

private JsonMapper getJackson() {
if (jacksonCache == null || !(jacksonCache instanceof JsonMapper)) {
protected JsonMapper getMapper() {
JsonMapper mapper = this.mapper;
if (mapper == null) {
synchronized (this) {
if (jacksonCache == null || !(jacksonCache instanceof JsonMapper)) {
jacksonCache = JsonMapper.builder()
.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.serializationInclusion(Include.NON_NULL)
.addModule(new JavaTimeModule())
.build();
mapper = this.mapper;
if (mapper == null) {
this.mapper = mapper = createBuilder().build();
}
}
}
return (JsonMapper) jacksonCache;
return mapper;
}

protected Builder createBuilder() {
return JsonMapper.builder()
.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.serializationInclusion(Include.NON_NULL)
.addModule(new JavaTimeModule());
}
}
Loading

0 comments on commit 4a4d756

Please sign in to comment.