package cn.iocoder.yudao.framework.common.util.json;
|
|
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.json.JSONUtil;
|
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
|
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
import lombok.Getter;
|
import lombok.SneakyThrows;
|
import lombok.extern.slf4j.Slf4j;
|
import tools.jackson.core.JacksonException;
|
import tools.jackson.core.type.TypeReference;
|
import tools.jackson.databind.DeserializationFeature;
|
import tools.jackson.databind.JsonNode;
|
import tools.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.SerializationFeature;
|
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.module.SimpleModule;
|
|
import java.lang.reflect.Type;
|
import java.time.LocalDateTime;
|
import java.util.ArrayList;
|
import java.util.List;
|
|
/**
|
* JSON 工具类
|
*
|
* @author 芋道源码
|
*/
|
@Slf4j
|
public class JsonUtils {
|
|
@Getter
|
private static ObjectMapper objectMapper = buildObjectMapper();
|
|
private static ObjectMapper buildObjectMapper() {
|
SimpleModule simpleModule = new SimpleModule()
|
.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
|
.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
|
return JsonMapper.builder()
|
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
|
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
// 强制将整数反序列化为 Long,解决 Redis 缓存反序列化时 Integer 转 Long 的问题
|
.enable(DeserializationFeature.USE_LONG_FOR_INTS)
|
.changeDefaultPropertyInclusion(value -> JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL))
|
.addModule(simpleModule)
|
.build();
|
}
|
|
/**
|
* 初始化 objectMapper 属性
|
* <p>
|
* 通过这样的方式,使用 Spring 创建的 ObjectMapper Bean
|
*
|
* @param objectMapper ObjectMapper 对象
|
*/
|
public static void init(ObjectMapper objectMapper) {
|
JsonUtils.objectMapper = objectMapper;
|
}
|
|
@SneakyThrows
|
public static String toJsonString(Object object) {
|
return objectMapper.writeValueAsString(object);
|
}
|
|
@SneakyThrows
|
public static byte[] toJsonByte(Object object) {
|
return objectMapper.writeValueAsBytes(object);
|
}
|
|
@SneakyThrows
|
public static String toJsonPrettyString(Object object) {
|
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
|
}
|
|
public static <T> T parseObject(String text, Class<T> clazz) {
|
if (StrUtil.isEmpty(text)) {
|
return null;
|
}
|
try {
|
return objectMapper.readValue(text, clazz);
|
} catch (JacksonException e) {
|
log.error("json parse err,json:{}", text, e);
|
throw new RuntimeException(e);
|
}
|
}
|
|
public static <T> T parseObject(String text, String path, Class<T> clazz) {
|
if (StrUtil.isEmpty(text)) {
|
return null;
|
}
|
try {
|
JsonNode treeNode = objectMapper.readTree(text);
|
JsonNode pathNode = treeNode.path(path);
|
return objectMapper.readValue(pathNode.toString(), clazz);
|
} catch (JacksonException e) {
|
log.error("json parse err,json:{}", text, e);
|
throw new RuntimeException(e);
|
}
|
}
|
|
public static <T> T parseObject(String text, Type type) {
|
if (StrUtil.isEmpty(text)) {
|
return null;
|
}
|
try {
|
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructType(type));
|
} catch (JacksonException e) {
|
log.error("json parse err,json:{}", text, e);
|
throw new RuntimeException(e);
|
}
|
}
|
|
public static <T> T parseObject(byte[] text, Type type) {
|
if (ArrayUtil.isEmpty(text)) {
|
return null;
|
}
|
try {
|
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructType(type));
|
} catch (JacksonException e) {
|
log.error("json parse err,json:{}", text, e);
|
throw new RuntimeException(e);
|
}
|
}
|
|
/**
|
* 将字符串解析成指定类型的对象
|
* 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下,
|
* 如果 text 没有 class 属性,则会报错。此时,使用这个方法,可以解决。
|
*
|
* @param text 字符串
|
* @param clazz 类型
|
* @return 对象
|
*/
|
public static <T> T parseObject2(String text, Class<T> clazz) {
|
if (StrUtil.isEmpty(text)) {
|
return null;
|
}
|
return JSONUtil.toBean(text, clazz);
|
}
|
|
public static <T> T parseObject(byte[] bytes, Class<T> clazz) {
|
if (ArrayUtil.isEmpty(bytes)) {
|
return null;
|
}
|
try {
|
return objectMapper.readValue(bytes, clazz);
|
} catch (JacksonException e) {
|
log.error("json parse err,json:{}", bytes, e);
|
throw new RuntimeException(e);
|
}
|
}
|
|
public static <T> T parseObject(String text, TypeReference<T> typeReference) {
|
try {
|
return objectMapper.readValue(text, typeReference);
|
} catch (JacksonException e) {
|
log.error("json parse err,json:{}", text, e);
|
throw new RuntimeException(e);
|
}
|
}
|
|
/**
|
* 解析 JSON 字符串成指定类型的对象,如果解析失败,则返回 null
|
*
|
* @param text 字符串
|
* @param typeReference 类型引用
|
* @return 指定类型的对象
|
*/
|
public static <T> T parseObjectQuietly(String text, TypeReference<T> typeReference) {
|
try {
|
return objectMapper.readValue(text, typeReference);
|
} catch (JacksonException e) {
|
return null;
|
}
|
}
|
|
/**
|
* 解析 JSON 字符串成指定类型的对象,如果解析失败,则返回 null
|
*
|
* @param text 字符串
|
* @param clazz 类型
|
* @return 指定类型的对象
|
*/
|
public static <T> T parseObjectQuietly(String text, Class<T> clazz) {
|
if (StrUtil.isEmpty(text)) {
|
return null;
|
}
|
try {
|
return objectMapper.readValue(text, clazz);
|
} catch (JacksonException e) {
|
return null;
|
}
|
}
|
|
public static <T> List<T> parseArray(String text, Class<T> clazz) {
|
if (StrUtil.isEmpty(text)) {
|
return new ArrayList<>();
|
}
|
try {
|
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
|
} catch (JacksonException e) {
|
log.error("json parse err,json:{}", text, e);
|
throw new RuntimeException(e);
|
}
|
}
|
|
public static <T> List<T> parseArray(String text, String path, Class<T> clazz) {
|
if (StrUtil.isEmpty(text)) {
|
return null;
|
}
|
try {
|
JsonNode treeNode = objectMapper.readTree(text);
|
JsonNode pathNode = treeNode.path(path);
|
return objectMapper.readValue(pathNode.toString(), objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
|
} catch (JacksonException e) {
|
log.error("json parse err,json:{}", text, e);
|
throw new RuntimeException(e);
|
}
|
}
|
|
public static JsonNode parseTree(String text) {
|
try {
|
return objectMapper.readTree(text);
|
} catch (JacksonException e) {
|
log.error("json parse err,json:{}", text, e);
|
throw new RuntimeException(e);
|
}
|
}
|
|
public static JsonNode parseTree(byte[] text) {
|
try {
|
return objectMapper.readTree(text);
|
} catch (JacksonException e) {
|
log.error("json parse err,json:{}", text, e);
|
throw new RuntimeException(e);
|
}
|
}
|
|
public static boolean isJson(String text) {
|
return JSONUtil.isTypeJSON(text);
|
}
|
|
/**
|
* 判断字符串是否为 JSON 类型的字符串
|
* @param str 字符串
|
*/
|
public static boolean isJsonObject(String str) {
|
return JSONUtil.isTypeJSONObject(str);
|
}
|
|
/**
|
* 将 Object 转换为目标类型
|
* <p>
|
* 避免先转 jsonString 再 parseObject 的性能损耗
|
*
|
* @param obj 源对象(可以是 Map、POJO 等)
|
* @param clazz 目标类型
|
* @return 转换后的对象
|
*/
|
public static <T> T convertObject(Object obj, Class<T> clazz) {
|
if (obj == null) {
|
return null;
|
}
|
if (clazz.isInstance(obj)) {
|
return clazz.cast(obj);
|
}
|
return objectMapper.convertValue(obj, clazz);
|
}
|
|
/**
|
* 将 Object 转换为目标类型(支持泛型)
|
*
|
* @param obj 源对象
|
* @param typeReference 目标类型引用
|
* @return 转换后的对象
|
*/
|
public static <T> T convertObject(Object obj, TypeReference<T> typeReference) {
|
if (obj == null) {
|
return null;
|
}
|
return objectMapper.convertValue(obj, typeReference);
|
}
|
|
/**
|
* 将 Object 转换为 List 类型
|
* <p>
|
* 避免先转 jsonString 再 parseArray 的性能损耗
|
*
|
* @param obj 源对象(可以是 List、数组等)
|
* @param clazz 目标元素类型
|
* @return 转换后的 List
|
*/
|
public static <T> List<T> convertList(Object obj, Class<T> clazz) {
|
if (obj == null) {
|
return new ArrayList<>();
|
}
|
return objectMapper.convertValue(obj, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
|
}
|
|
}
|