Java中Jackson的序列化与反序列化详解

 更新时间:2024年01月27日 09:39:25   作者:魅Lemon  
这篇文章主要介绍了Java中Jackson的序列化与反序列化详解,Jackson被认为是"Java JSON库"或"Java最好的JSON解析器",Jackson 还是一套用于 Java(和 JVM 平台)的数据处理工具,需要的朋友可以参考下

一、Jackson简介

1、什么是Jackson

Jackson被认为是"Java JSON库"或"Java最好的JSON解析器"。或简单地被当作"JSON for Java"。不仅如此,Jackson 还是一套用于 Java(和 JVM 平台)的数据处理工具,包括流式 JSON parser / generator库、匹配 data-binding 库(POJO和JSON相互转换),还有一个额外的 data format 模块来处理 Avro, BSON, CBOR, CSV, Smile, (Java) Properties, Protobuf, TOML, XML, YAML 这些数据编码,甚至还有大量的数据格式模块,来支持被广泛使用的数据类型如 Guava, Joda, PCollections 等等

核心组件存在于他们自己的项目下,包括三个核心包(streaming, databind, annotations);数据格式库;数据类型库;JAX-RS provider;和一个复杂的扩展模块—这个project 连接各个模块的中心枢纽

2、核心模块

核心模块是扩展(模块)构建的基础。目前有3个模块 (Jackson 2.x为例) :

  • Streaming (docs) (“jackson-core”) 定义低级流 API,并包括 JSON 具体实现
  • Annotations (docs) (“jackson-annotations”) 包含标准 Jackson 注解
  • Databind (docs) (“jackson-databind”) 实现data-binding (和 object serialization) ,支持 streaming 包; 它依赖于 streaming 和 annotations 包

二、ObjectMapper常见使用

ObjectMapper类(com.fasterxml.jackson.databind.ObjectMapper)是Jackson的主要类,它可以帮助我们快速的进行各个类型和Json类型的相互转换

1、ObjectMapper的常用配置

private static final ObjectMapper mapper;
public static ObjectMapper getObjectMapper(){
    return this.mapper;
}
static{
    //创建ObjectMapper对象
    mapper = new ObjectMapper()
    //configure方法 配置一些需要的参数
    // 转换为格式化的json 显示出来的格式美化
    mapper.enable(SerializationFeature.INDENT_OUTPUT);
    //序列化的时候序列对象的那些属性  
    //JsonInclude.Include.NON_DEFAULT 属性为默认值不序列化 
    //JsonInclude.Include.ALWAYS      所有属性
    //JsonInclude.Include.NON_EMPTY   属性为 空(“”) 或者为 NULL 都不序列化 
    //JsonInclude.Include.NON_NULL    属性为NULL 不序列化
    mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);  
    //反序列化时,遇到未知属性会不会报错 
    //true - 遇到没有的属性就报错 false - 没有的属性不会管,不会报错
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    //如果是空对象的时候,不抛异常  
    mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);  
    // 忽略 transient 修饰的属性
    mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
    //修改序列化后日期格式
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);  
    mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    //处理不同的时区偏移格式
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    mapper.registerModule(new JavaTimeModule());
}

2、ObjectMapper的常用方法

2.1 json字符串转对象

ObjectMapper mapper = new ObjectMapper();
String jsonString = "{\"name\":\"shawn\", \"age\":20}";
//将字符串转换为对象
Student student = mapper.readValue(jsonString, Student.class);
System.out.println(student);
//将对象转换为json字符串
jsonString = mapper.writeValueAsString(student);
System.out.println(jsonString);

2.2 数组和对象之间转换

//对象转为byte数组
byte[] byteArr = mapper.writeValueAsBytes(student);
System.out.println(byteArr);
//byte数组转为对象
Student student= mapper.readValue(byteArr, Student.class);
System.out.println(student);
结果:
[B@3327bd23
Student [ name: shawn, age: 20 ]

结果:

Student [ name: shawn, age: 20 ]
{
  "name" : "Hyl",
  "age" : 20
}

2.3 集合和json字符串之间转换

List<Student> studentList= new ArrayList<>();
studentList.add(new Student("shawn1" ,20 , new Date()));
studentList.add(new Student("shawn2" ,21 , new Date()));
studentList.add(new Student("shawn3" ,22 , new Date()));
studentList.add(new Student("shawn4" ,23 , new Date()));
 
String jsonStr = mapper.writeValueAsString(studentList);
System.out.println(jsonStr);
        
List<Student> studentList2 = mapper.readValue(jsonStr, List.class);
System.out.println("字符串转集合:" + studentList2 );
 

结果:

[ {
  "name" : "shawn1",
  "age" : 20,
  "sendTime" : 1525164212803
}, {
  "name" : "shawn2",
  "age" : 21,
  "sendTime" : 1525164212803
}, {
  "name" : "shawn3",
  "age" : 22,
  "sendTime" : 1525164212803
}, {
  "name" : "shawn4",
  "age" : 23,
  "sendTime" : 1525164212803
} ]
[{name=shawn1, age=20, sendTime=1525164212803}, {name=shawn2, age=21, sendTime=1525164212803}, {name=shawn3, age=22, sendTime=1525164212803}, {name=shawn4, age=23, sendTime=1525164212803}]

2.4 map和json字符串之间转换

Map<String, Object> testMap = new HashMap<>();
testMap.put("name", "22");
testMap.put("age", 20);
testMap.put("date", new Date());
testMap.put("student", new Student("shawn", 20, new Date()));
 
 
String jsonStr = mapper.writeValueAsString(testMap);
System.out.println(jsonStr);
Map<String, Object> testMapDes = mapper.readValue(jsonStr, Map.class);
System.out.println(testMapDes);

 结果:

{
  "date" : 1525164212803,
  "name" : "22",
  "student" : {
    "name" : "shawn",
    "age" : 20,
    "sendTime" : 1525164212803,
    "intList" : null
  },
  "age" : 20
}
{date=1525164212803, name=22, student={name=shawn, age=20, sendTime=1525164212803, intList=null}, age=20}

2.5 日期转json字符串

// 修改时间格式
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
Student student = new Student ("shawn",21, new Date());
student.setIntList(Arrays.asList(1, 2, 3));

String jsonStr = mapper.writeValueAsString(student);
System.out.println(jsonStr);

结果:

{
  "name" : "shawn",
  "age" : 21,
  "sendTime" : "2020-07-23 13:14:36",
  "intList" : [ 1, 2, 3 ]
}

2.6 readTree()方法

此方法更灵活,可以只将用户感兴趣的Json串信息值提取出来。主要利用ObjectMapper提供的readTree和Jackson提供的JsonNode类来实现

String test="{"results":[{"objectID":357,"geoPoints":[{"x":504604.59802246094,"y":305569.9150390625}]},{"objectID":358,"geoPoints":[{"x":504602.2680053711,"y":305554.43603515625}]}]}";
//此Json串比较复杂,包含了嵌套数组的形式,具有通用性。
//2.2.2.2实现反序列化
JsonNode node= objectMapper.readTree(test); //将Json串以树状结构读入内存
JsonNode contents=node.get("results");//得到results这个节点下的信息
//遍历results下的信息,size()函数可以得节点所包含的的信息的个数,类似于数组的长度
for(int i=0;i<contents.size();i++)  {
    //读取节点下的某个子节点的值
    System.out.println(contents.get(i).get("objectID").getIntValue());
    JsonNode geoNumber=contents.get(i).get("geoPoints");
    //循环遍历子节点下的信息
    for(int j=0;j<geoNumber.size();j++){
        System.out.println(geoNumber.get(j).get("x").getDoubleValue()+"  "+geoNumber.get(j).get("y").getDoubleValue());
    }
}

3、Java Web与ObjectMapper

在开发 Spring Web 应用程序时,如果自定义了 ObjectMapper,并把它注册成了Bean,那很可能会导致 Spring Web 使用的 ObjectMapper 也被替换,导致 Bug。

例如下面的bean,注册到Spring后就会把Spring原有的配置覆盖,导致原有的序列化配置丢失

@Bean
public ObjectMapper objectMapper(){
    ObjectMapper objectMapper=new ObjectMapper();
    objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,true);
    return objectMapper;
}

针对这个问题,有三种解决方法

  • 使用objectMapper.configure(SerializationFeature.xxx,true);把配置补齐
  • 设置自定义类型,加上 @JsonIgnoreProperties 注解,开启 ignoreUnknown 属性,以实现反序列化时忽略额外的数据
  • 不要自定义 ObjectMapper,而是直接在配置文件设置相关参数,来修改 Spring 默认的 ObjectMapper 的功能,例如:spring.jackson.serialization.write_enums_using_index=true

另外,通过查找JacksonProperties类源码,可以发现很多配置类的属性,可以配合使用

4、Redis序列化的一个例子

@Bean
public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(redisConnectionFactory);
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.enable(DeserializationFeature.USE_LONG_FOR_INTS);
    //把类型信息作为属性写入Value
    objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
    redisTemplate.setKeySerializer(RedisSerializer.string());
    redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
    redisTemplate.setHashKeySerializer(RedisSerializer.string());
    redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
    redisTemplate.afterPropertiesSet();
    return redisTemplate;
}

到此这篇关于Java中Jackson的序列化与反序列化详解的文章就介绍到这了,更多相关Jackson的序列化与反序列化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java设计模式之责任链模式详解

    Java设计模式之责任链模式详解

    这篇文章主要介绍了Java设计模式之责任链模式详解,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • Java小项目之迷宫游戏的实现方法

    Java小项目之迷宫游戏的实现方法

    这篇文章主要给大家介绍了关于Java小项目之迷宫的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Java Process类的详解及实例代码

    Java Process类的详解及实例代码

    这篇文章主要介绍了Java Process类的详解及实例代码的相关资料,需要的朋友可以参考下
    2017-02-02
  • java.lang.Void类源码解析

    java.lang.Void类源码解析

    这篇文章主要介绍了java.lang.Void类源码解析的相关内容,对源码中的部分内容进行解释,具有一定参考价值,需要的朋友可以了解下。
    2017-10-10
  • Java反射获取所有Controller和RestController类的方法

    Java反射获取所有Controller和RestController类的方法

    这篇文章给大家分享了Java反射获取所有Controller和RestController类的方法,文中有详细的代码示例讲解,具有一定的参考价值,需要的朋友可以参考下
    2023-08-08
  • Spring Boot项目完美大一统(结果异常日志统一)

    Spring Boot项目完美大一统(结果异常日志统一)

    这篇文章主要为大家介绍了Spring Boot项目完美大一统(结果异常日志统一)的实详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • Java中的static和final关键字的使用详解

    Java中的static和final关键字的使用详解

    这篇文章主要介绍了Java中的static和final关键字的使用详解,  当方法名前有static,即为static方法,可以方便我们无需创建对象也可以调用此方法,静态方法比较拉,只可以访问 静态的 属性/变量/方法,无法访问非静态的这些属性/变量/方法,需要的朋友可以参考下
    2024-01-01
  • 浅谈Mybatis通用Mapper使用方法

    浅谈Mybatis通用Mapper使用方法

    本篇文章主要介绍了浅谈Mybatis通用Mapper使用方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • Javacv使用ffmpeg实现音视频同步播放

    Javacv使用ffmpeg实现音视频同步播放

    这篇文章主要介绍了Javacv使用ffmpeg实现音视频同步播放,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • Java使用JSONObject操作json实例解析

    Java使用JSONObject操作json实例解析

    这篇文章主要介绍了Java使用JSONObject操作json,结合实例形式较为详细的分析了Java使用JSONObject解析json数据相关原理、使用技巧与操作注意事项,需要的朋友可以参考下
    2020-04-04

最新评论