package com.njupt.swg.utils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.type.TypeReference; import java.io.IOException; import java.text.SimpleDateFormat; /** * jackson的序列化和反序列化 * 该类是一个工具类,主要基于Jackson库提供了一系列用于对象序列化(将对象转换为JSON字符串)和反序列化(将JSON字符串转换为对象)的方法, * 同时在类的初始化阶段对Jackson的ObjectMapper进行了一些配置,以满足项目中特定的JSON处理需求,例如统一日期格式、忽略某些转换错误等。 */ @Slf4j public class JsonUtil { // 创建一个ObjectMapper对象,它是Jackson库中用于进行JSON序列化和反序列化操作的核心类,后续的各种序列化和反序列化操作都依赖它来实现。 private static ObjectMapper objectMapper = new ObjectMapper(); static { //所有字段都列入进行转换 // 设置ObjectMapper在序列化时的包含规则,这里设置为JsonSerialize.Inclusion.ALWAYS,表示所有的字段都会被包含进序列化的结果中, // 即使字段的值为null也会进行序列化处理,确保完整的对象结构能在JSON字符串中体现出来。 objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.ALWAYS); //取消默认转换timestamp形式 // 配置ObjectMapper在序列化日期类型字段时,取消将日期转换为时间戳的默认行为,这样在序列化后的JSON字符串中日期会以指定的格式呈现,而不是时间戳形式。 objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false); //忽略空bean转json的错误 // 配置ObjectMapper在尝试将一个空的Java对象(没有任何属性值的对象)转换为JSON字符串时,忽略可能出现的错误, // 使得即使对象为空也能正常进行序列化操作,避免抛出异常导致程序中断。 objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false); //统一时间的格式 // 设置ObjectMapper在处理日期类型数据时使用的统一日期格式,通过传入一个SimpleDateFormat对象,指定了格式为DateTimeUtil.STANDARD_FORMAT(在其他地方定义的标准格式), // 保证序列化和反序列化过程中日期格式的一致性和规范性。 objectMapper.setDateFormat(new SimpleDateFormat(DateTimeUtil.STANDARD_FORMAT)); //忽略json存在属性,但是java对象不存在属性的错误 // 配置ObjectMapper在进行反序列化时,忽略JSON字符串中存在但对应的Java对象中不存在的属性所引发的错误, // 这样在JSON数据结构可能发生变化或者不完全匹配Java对象结构时,依然能够正常进行反序列化操作,提高了程序的兼容性和容错性。 objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); } /** * 序列化方法,将对象转为字符串 * 该方法用于将一个Java对象转换为JSON字符串表示形式,如果对象为null则直接返回null, * 在转换过程中若出现IO异常(例如对象的某些属性无法正常序列化等情况),会记录警告日志并返回null。 * * @param obj 要进行序列化的Java对象,可以是任意类型的对象,由泛型参数表示其通用性。 * @param 泛型参数,用于表示传入对象的类型,确保返回的JSON字符串能正确对应相应类型的对象序列化结果。 * @return 返回转换后的JSON字符串,如果对象为null或者序列化过程出现异常则返回null。 */ public static String obj2String(T obj) { if (obj == null) { return null; } try { // 判断传入的对象是否本身就是字符串类型,如果是则直接返回该字符串,否则使用ObjectMapper将对象转换为JSON字符串并返回。 return obj instanceof String? (String) obj : objectMapper.writeValueAsString(obj); } catch (IOException e) { log.warn("parse object to string error", e); return null; } } /** * 序列化方法,同上,只是输出的格式是美化的,便于测试 * 该方法与obj2String方法功能类似,也是将Java对象转换为JSON字符串,不同之处在于它会使用美化的格式输出JSON字符串, * 使得生成的JSON字符串更易于阅读和查看,方便在测试等场景下查看对象序列化后的具体结构,同样在出现异常时会记录警告日志并返回null。 * * @param obj 要进行序列化的Java对象,可以是任意类型的对象,由泛型参数表示其通用性。 * @param 泛型参数,用于表示传入对象的类型,确保返回的JSON字符串能正确对应相应类型的对象序列化结果。 * @return 返回转换后的JSON字符串,如果对象为null或者序列化过程出现异常则返回null,正常情况下返回美化格式的JSON字符串。 */ public static String obj2StringPretty(T obj) { if (obj == null) { return null; } try { // 使用ObjectMapper的writerWithDefaultPrettyPrinter方法获取一个能够生成美化格式JSON字符串的写入器, // 然后通过该写入器将对象转换为美化后的JSON字符串并返回。 return obj instanceof String? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj); } catch (IOException e) { log.warn("parse object to string error", e); return null; } } /** * 比较简单的反序列化的方法,将字符串转为单个对象 * 该方法用于将一个JSON字符串反序列化为指定类型的Java对象,在进行反序列化前会先判断字符串是否为空以及指定的目标类是否为null, * 如果有任意一个为空则直接返回null,若反序列化过程中出现IO异常(例如JSON格式不匹配目标对象结构等情况),会记录警告日志并返回null。 * * @param str 要进行反序列化的JSON字符串,包含了要转换为Java对象的数据内容。 * @param clazz 目标Java对象的类型,通过传入的Class参数明确指定要将JSON字符串反序列化为哪种类型的对象,确保类型的准确性。 * @param 泛型参数,用于表示要反序列化得到的对象类型,与传入的clazz参数类型相对应。 * @return 返回反序列化后的Java对象,如果字符串为空、目标类为null或者反序列化过程出现异常则返回null。 */ public static T String2Obj(String str, Class clazz) { if (StringUtils.isEmpty(str) || clazz == null) { return null; } try { // 判断传入的目标类是否就是字符串类型的Class对象,如果是则直接将传入的字符串强制转换并返回(因为本身就是字符串无需真正的反序列化操作), // 否则使用ObjectMapper将JSON字符串按照指定的目标类进行反序列化并返回对应的对象。 return clazz.equals(String.class)? (T) str : objectMapper.readValue(str, clazz); } catch (IOException e) { log.warn("parse string to obj error", e); return null; } } /** * 复杂对象的反序列化(通用) * 该方法用于处理更复杂的反序列化场景,能够将JSON字符串反序列化为复杂类型的对象(例如包含泛型的集合类型等), * 通过传入TypeReference类型的参数来指定复杂对象的具体类型信息,同样在字符串为空或者TypeReference为null时会直接返回null, * 若反序列化出现异常会记录警告日志并返回null。 * * @param str 要进行反序列化的JSON字符串,包含了要转换为复杂Java对象的数据内容。 * @param typeReference 用于指定复杂对象类型的TypeReference对象,通过它可以准确描述包含泛型等复杂结构的对象类型信息,确保反序列化的准确性。 * @param 泛型参数,用于表示要反序列化得到的复杂对象类型,与传入的typeReference所描述的类型相对应。 * @return 返回反序列化后的复杂Java对象,如果字符串为空、typeReference为null或者反序列化过程出现异常则返回null。 */ public static T Str2Obj(String str, TypeReference typeReference) { if (StringUtils.isEmpty(str) || typeReference == null) { return null; } try { // 判断传入的TypeReference所表示的类型是否就是字符串类型,如果是则直接返回传入的字符串(无需反序列化操作), // 否则使用ObjectMapper按照TypeReference指定的复杂类型信息将JSON字符串进行反序列化并返回对应的对象。 return (T) (typeReference.getType().equals(String.class)? str : objectMapper.readValue(str, typeReference)); } catch (IOException e) { log.warn("parse string to obj error", e); return null; } } /** * 第二种方式实现复杂对象的反序列化 * 该方法是另一种实现复杂对象反序列化的方式,通过传入集合类型的Class对象以及元素类型的Class对象(可以多个,用于表示集合中元素的类型信息), * 利用ObjectMapper的类型工厂构建出JavaType对象来准确描述复杂对象的类型结构,然后进行反序列化操作, * 在出现异常时同样会记录警告日志并返回null。 * * @param str 要进行反序列化的JSON字符串,包含了要转换为复杂Java对象的数据内容。 * @param collectionClass 表示集合类型的Class对象,用于指定要反序列化得到的对象是哪种集合类型(如List、Set等)。 * @param elementClasses 可变参数,用于指定集合中元素的类型Class对象,可以传入多个,按照顺序依次表示集合中各元素的类型信息。 * @param 泛型参数,用于表示要反序列化得到的复杂对象类型,与传入的collectionClass和elementClasses所构建的类型结构相对应。 * @return 返回反序列化后的复杂Java对象,如果反序列化过程出现异常则返回null。 */ public static T Str2Obj(String str, Class collectionClass, Class... elementClasses) { JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses); try { return objectMapper.readValue(str, javaType); } catch (IOException e) { log.warn("parse string to obj error", e); return null; } } }