Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support users to customize JsonUtil #14508

Merged
merged 7 commits into from
Sep 6, 2024
Merged
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
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
Loading