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; /** * @Author 作者信息(如果有) * @Date 创建日期(如果有) * @CONTACT 联系方式(如果有) * @DESC 这个类(JsonUtil)主要用于处理Jackson库相关的序列化和反序列化操作,是对Jackson功能的一个简单封装,方便在项目中统一地将Java对象转换为JSON字符串(序列化)以及将JSON字符串转换为Java对象(反序列化)。 * 它通过配置ObjectMapper对象的一些属性来定制序列化和反序列化的行为,例如控制哪些字段参与转换、时间格式的处理以及如何处理一些可能出现的转换错误等情况,并且使用了@Slf4j注解来记录在操作过程中出现的相关警告等日志信息。 */ @Slf4j public class JsonUtil { // 创建一个ObjectMapper对象,它是Jackson库中用于进行JSON序列化和反序列化的核心类,后续通过配置它的各种属性来实现特定的序列化和反序列化规则。 private static ObjectMapper objectMapper = new ObjectMapper(); // 静态代码块,在类加载时执行,用于对ObjectMapper对象进行一系列的配置操作,以定制其序列化和反序列化的行为。 static { // 设置序列化时包含的字段规则,这里设置为JsonSerialize.Inclusion.ALWAYS,表示所有字段都列入进行转换,即无论字段值是否为null,都会包含在序列化生成的JSON字符串中。 objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.ALWAYS); // 取消默认将日期类型转换为时间戳(timestamp)形式的行为,这样在序列化日期对象时,会按照后续配置的日期格式进行转换,而不是转换为时间戳格式。 objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false); // 忽略在序列化空的Java Bean(即没有属性值的对象)转JSON字符串时可能出现的错误,使得即使对象为空,也能尝试进行序列化操作,避免抛出异常。 objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false); // 统一设置时间的格式,通过传入一个SimpleDateFormat对象,并指定格式为DateTimeUtil类中定义的标准格式("yyyy-MM-dd HH:mm:ss"),使得在序列化和反序列化日期对象时,都按照这个标准格式进行处理。 objectMapper.setDateFormat(new SimpleDateFormat(DateTimeUtil.STANDARD_FORMAT)); // 忽略在反序列化JSON字符串时,如果JSON中存在的属性但对应的Java对象不存在该属性的这种错误情况,使得即使JSON数据和Java对象结构不完全匹配,也能尽量进行反序列化操作,避免因属性不匹配而抛出异常。 objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); } /** * 序列化方法,用于将Java对象转换为JSON字符串。 * 如果传入的对象为null,则直接返回null。如果对象本身就是String类型,则直接返回该字符串(因为本身已经是符合要求的字符串形式了),否则使用ObjectMapper对象将对象转换为JSON字符串,若转换过程中出现IO异常,则记录警告日志并返回null。 * @param obj 要进行序列化的Java对象,其类型可以是任意Java类,只要该类能被Jackson库正确序列化(即符合Jackson序列化的相关规则,比如有合适的Getter、Setter方法等)。 * @param 泛型参数,表示传入对象的类型,这里主要用于方法定义的通用性,使得可以处理各种类型的对象序列化。 * @return 返回序列化后的JSON字符串,如果传入对象为null或者序列化过程出现异常则返回null。 */ public static String obj2String(T obj) { if (obj == null) { return null; } try { 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字符串格式是美化后的,更便于查看和测试(例如会进行缩进、换行等格式化处理)。 * 如果传入的对象为null,则直接返回null。如果对象本身就是String类型,则直接返回该字符串,否则使用ObjectMapper对象的美化打印功能将对象转换为格式化后的JSON字符串,若转换过程中出现IO异常,则记录警告日志并返回null。 * @param obj 要进行序列化的Java对象,其类型可以是任意Java类,只要该类能被Jackson库正确序列化。 * @param 泛型参数,表示传入对象的类型,用于方法定义的通用性。 * @return 返回序列化后的、经过美化的JSON字符串,如果传入对象为null或者序列化过程出现异常则返回null。 */ public static String obj2StringPretty(T obj) { if (obj == null) { return null; } try { 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对象。 * 如果传入的JSON字符串为空或者要转换的目标Java类(clazz)为null,则直接返回null。如果目标类是String类型,且传入的字符串不为空,则直接将该字符串作为结果返回(因为本身就是符合要求的字符串形式了),否则使用ObjectMapper对象将JSON字符串转换为指定类型的Java对象,若转换过程中出现IO异常,则记录警告日志并返回null。 * @param str 要进行反序列化的JSON字符串,需要符合Jackson库反序列化的格式要求,即与对应的Java对象结构能够匹配(根据配置可能允许一定的属性差异情况)。 * @param clazz 要转换生成的目标Java对象的类型,通过传入的Class对象来指定具体的类型,以便ObjectMapper能正确地将JSON数据转换为对应的Java对象实例。 * @param 泛型参数,表示目标Java对象的类型,用于方法定义的通用性,使得可以处理各种类型对象的反序列化。 * @return 返回反序列化后的Java对象,如果传入的JSON字符串为空、目标类为null或者转换过程出现异常则返回null。 */ public static T String2Obj(String str, Class clazz) { if (StringUtils.isEmpty(str) || clazz == null) { return null; } try { 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字符串到Java对象的转换,通过TypeReference来指定复杂的类型信息。 * 如果传入的JSON字符串为空或者TypeReference对象为null,则直接返回null。如果TypeReference表示的类型是String类型,且传入的字符串不为空,则直接将该字符串作为结果返回,否则使用ObjectMapper对象根据TypeReference指定的复杂类型信息将JSON字符串转换为对应的Java对象,若转换过程中出现IO异常,则记录警告日志并返回null。 * @param str 要进行反序列化的JSON字符串,需要符合对应的复杂类型结构要求以及Jackson库反序列化的相关规则。 * @param typeReference TypeReference对象,用于指定复杂的Java对象类型信息,例如可以是包含泛型的集合类型、嵌套的复杂对象类型等,使得ObjectMapper能准确地进行反序列化操作。 * @param 泛型参数,表示要转换生成的复杂Java对象的类型,用于方法定义的通用性。 * @return 返回反序列化后的复杂Java对象,如果传入的JSON字符串为空、TypeReference对象为null或者转换过程出现异常则返回null。 */ public static T Str2Obj(String str, TypeReference typeReference) { if (StringUtils.isEmpty(str) || typeReference == null) { return null; } try { 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; } } /** * 第二种方式实现复杂对象的反序列化方法,通过传入集合类(collectionClass)以及元素类(elementClasses)的Class对象来构建JavaType对象,进而指定复杂的类型结构,然后使用ObjectMapper将JSON字符串转换为对应的复杂Java对象。 * 如果转换过程中出现IO异常,则记录警告日志并返回null。 * @param str 要进行反序列化的JSON字符串,需要符合根据传入的类型信息构建的复杂类型结构以及Jackson库反序列化的相关规则。 * @param collectionClass 表示集合类型的Class对象,例如List.class、Set.class等,用于指定要转换生成的复杂对象中最外层的集合类型。 * @param elementClasses 可变参数,表示集合中元素的类型的Class对象,按照顺序依次指定集合中元素的类型,用于构建复杂的嵌套类型结构,例如对于List,第一个参数是List.class,第二个参数是String.class。 * @param 泛型参数,表示要转换生成的复杂Java对象的类型,用于方法定义的通用性。 * @return 返回反序列化后的复杂Java对象,如果转换过程中出现IO异常则返回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; } } }