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 属性
*
* 通过这样的方式,使用 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 parseObject(String text, Class 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 parseObject(String text, String path, Class 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 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 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 parseObject2(String text, Class clazz) {
if (StrUtil.isEmpty(text)) {
return null;
}
return JSONUtil.toBean(text, clazz);
}
public static T parseObject(byte[] bytes, Class 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 parseObject(String text, TypeReference 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 parseObjectQuietly(String text, TypeReference typeReference) {
try {
return objectMapper.readValue(text, typeReference);
} catch (JacksonException e) {
return null;
}
}
/**
* 解析 JSON 字符串成指定类型的对象,如果解析失败,则返回 null
*
* @param text 字符串
* @param clazz 类型
* @return 指定类型的对象
*/
public static T parseObjectQuietly(String text, Class clazz) {
if (StrUtil.isEmpty(text)) {
return null;
}
try {
return objectMapper.readValue(text, clazz);
} catch (JacksonException e) {
return null;
}
}
public static List parseArray(String text, Class 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 List parseArray(String text, String path, Class 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 转换为目标类型
*
* 避免先转 jsonString 再 parseObject 的性能损耗
*
* @param obj 源对象(可以是 Map、POJO 等)
* @param clazz 目标类型
* @return 转换后的对象
*/
public static T convertObject(Object obj, Class 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 convertObject(Object obj, TypeReference typeReference) {
if (obj == null) {
return null;
}
return objectMapper.convertValue(obj, typeReference);
}
/**
* 将 Object 转换为 List 类型
*
* 避免先转 jsonString 再 parseArray 的性能损耗
*
* @param obj 源对象(可以是 List、数组等)
* @param clazz 目标元素类型
* @return 转换后的 List
*/
public static List convertList(Object obj, Class clazz) {
if (obj == null) {
return new ArrayList<>();
}
return objectMapper.convertValue(obj, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
}
}