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)); } }