Jackson使用
如何使用 Jackson
学习任何一个技术,它是什么,怎么用,为什么?
这篇文档主要简单讲述如何使用 Jackson 进行序列化以及反序列化
如果需要快速的进行序列化或者反序列化,请用ctrl +F 进行搜索关键字。
Maven
- 在这里要说一下,Springboot中本身就依赖于Jackson,详情:https://www.bilibili.com/video/BV1kj411R7Wx?t=1.3
- note: 在这里还是把maven地址贴出来,但这三个依赖的版本一定要统一,当初笔者用时,databind版本比其他两个包高一级,在序列化和反序列化时都会出现失败。
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.14.2</version> </dependency> <!--对LocalDateTime等jdk8时间日期api的转化支持--> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.14.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.14.2</version> </dependency> <!--对数据进行XML序列化和反序列化--> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency>
代码展示
测试类
/** * <P> * Jackson测试类,添加了各种数据类型,以便于测试序列化和反序列化 * </P> * @author unknown * @since 2023/07/31 15:43 */ @Data public class Test { private long longId; private String stringTest; private int intTest; private double doubleTest; private short shortTest; private byte byteTest; private char charTest; private List<String> listStringTest; /** * 以下注解都是用于XML格式的序列化和反序列化,删除不影响JSON格式的序列化和反序列化 * 在javaTimeModule中自定义过相关类型的JOSN格式序列化和反序列化 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonSerialize(using = LocalDateTimeSerializer.class) @JsonDeserialize(using = LocalDateTimeDeserializer.class) private LocalDateTime localDateTimeTest; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date dateTest; }
测试代码
/** * @author unknown <P> * @since 2023/07/31 03:38 <P> * Jackson还支持CBOR,MessagePack,YAML等格式的序列化和反序列化,笔者暂时没有这个需求,所有不在此demo内举例 */ public class JsonTest { private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; private static final ObjectMapper objectMapper = new ObjectMapper(); private static final XmlMapper xmlMapper = new XmlMapper(); static { // 自定义序列化对象 JavaTimeModule javaTimeModule = new JavaTimeModule(); // LocalDateTime 序列化 javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT))); // LocalDateTime 反序列化 javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT))); /** * 将在<P>globalConfigurationTest()</P>中诠释 */ // 字段自动匹配,以对象字段为标准,JSON串种多余的字段舍弃 objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 序列化后不包含null的字段 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); /* // 将对象字段的驼峰转下划线 objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); // 将对象字段的驼峰转下划线且全部字段转为大写 objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.UPPER_SNAKE_CASE);*/ /** * <P>序列化美化输出</P> * 此美化输出的作用体现于<P>每个字段占据一行</P>,类似在其他Json格式化网站一样的功能,方便阅读,生产线上不推荐此功能 */ objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true); // 注册自定义序列化对象 objectMapper.registerModule(javaTimeModule); } /** * <P>配置代码解释</P> * Note: 在开启以下两个配置后,反序列化将会失效,待琢磨 * <p> * 将对象字段的驼峰转下划线<P> * objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); * <p> * 将对象字段的驼峰转下划线且字段大写<P> * objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.UPPER_SNAKE_CASE); * * 相对于这种配置,最好是用在JavaBean上,因为大部分序列化都是正常格式,有部分特殊的对象可能需要字段格式转换 * @see com.example.blog.jacksontest.JacksonAnnotationEntityTest */ @Test public void globalConfigurationTest() throws JsonProcessingException { com.example.blog.jacksontest.Test test = new com.example.blog.jacksontest.Test(); test.setLongId(1L); // test.setStringTest(DATE_TIME_FORMAT); test.setIntTest(2); test.setDoubleTest(3.0); test.setShortTest((short) 44); test.setByteTest((byte) 1128); // test.setCharTest('A'); test.setLocalDateTimeTest(LocalDateTime.now()); test.setDateTest(new Date()); String string = objectMapper.writeValueAsString(test); /** * 将对象字段的驼峰转下划线且全部字段转为大写 * objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.UPPER_SNAKE_CASE); * { * "LONG_ID" : 1, * // String类型的字段注释掉,将不会序列化此字段 -> objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); * "INT_TEST" : 2, * "DOUBLE_TEST" : 3.0, * "SHORT_TEST" : 44, * "BYTE_TEST" : 104, * "CHAR_TEST" : "\u0000", char类型的字段也不注释掉,但此字段在java中有默认值 * "LOCAL_DATE_TIME_TEST" : "2023-08-01 03:17:23", * "DATE_TEST" : "2023-07-31 19:17:23" * } */ System.out.println(string); // 添加多余字段Test测试-> objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); String deserialized = "{\"Test\":1,\"longId\":1,\"stringTest\":\"yyyy-MM-dd HH:mm:ss\",\"intTest\":2," + "\"doubleTest\":3.0,\"shortTest\":-32768,\"byteTest\":104,\"charTest\":\"A\"," + "\"localDateTimeTest\":\"2023-08-31 22:26:43\",\"dateTest\":\"2023-07-31 14:26:43\"}"; com.example.blog.jacksontest.Test deserializedTest = objectMapper.readValue(deserialized, com.example.blog.jacksontest.Test.class); /** * 多余的字段Test已被自动舍弃 * Test(longId=1, stringTest=yyyy-MM-dd HH:mm:ss, intTest=2, doubleTest=3.0, shortTest=-32768, byteTest=104, * charTest=A, localDateTimeTest=2023-08-31T22:26:43, dateTest=Mon Jul 31 22:26:43 CST 2023) */ System.out.println(deserializedTest); } /** * <P>JavaBean序列化JSON串</P> * * <p>LocalDateTime<p> * 当对象序列化的时候,需要自定义JavaTimeModule的LocalDateTime格式并且注册JavaTimeModule: * JavaTimeModule javaTimeModule = new JavaTimeModule(); * javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT))); * objectMapper.registerModule(javaTimeModule); * * <p>Date</p> * 此属性序列化于反序列化时,需要在此对象字段加上@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss"),不推荐在JavaTimeModule中定义 * 因为SimpleDateFormat是线程不安全的,但是ObjectMapper对象是现场安全的,这样会导致ObjectMapper也是不安全的,错误的如下 * SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); * objectMapper.setDateFormat(dateFormat); */ @Test public void javaBeanSerialize() throws JsonProcessingException { com.example.blog.jacksontest.Test test = new com.example.blog.jacksontest.Test(); test.setLongId(1L); test.setStringTest(DATE_TIME_FORMAT); test.setIntTest(2); test.setDoubleTest(3.0); test.setShortTest((short) 44); test.setByteTest((byte) 1128); test.setCharTest('A'); ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("hello"); arrayList.add("world"); test.setListStringTest(arrayList); test.setLocalDateTimeTest(LocalDateTime.now()); test.setDateTest(new Date()); String string = objectMapper.writeValueAsString(test); System.out.println(string); } /** * <P>JavaBean转文件</P> */ @Test public void javaBeanToFile() throws IOException { com.example.blog.jacksontest.Test test = new com.example.blog.jacksontest.Test(); test.setLongId(1L); test.setStringTest(DATE_TIME_FORMAT); test.setIntTest(2); test.setDoubleTest(3.0); test.setShortTest((short) 44); test.setByteTest((byte) 1128); test.setCharTest('A'); test.setLocalDateTimeTest(LocalDateTime.now()); test.setDateTest(new Date()); //写到文件 objectMapper.writeValue(new File("src/main/resources/static/json.txt"), test); //从文件中读取 com.example.blog.jacksontest.Test read = objectMapper.readValue(new File("/json.txt"), com.example.blog.jacksontest.Test.class); System.out.println(read); } /** * <P>javaBean转字节流</P> */ @Test public void javaBeanToByte() throws IOException { com.example.blog.jacksontest.Test test = new com.example.blog.jacksontest.Test(); test.setLongId(1L); test.setStringTest(DATE_TIME_FORMAT); test.setIntTest(2); test.setDoubleTest(3.0); test.setShortTest((short) 44); test.setByteTest((byte) 1128); test.setCharTest('A'); test.setLocalDateTimeTest(LocalDateTime.now()); test.setDateTest(new Date()); // 写为字节流 byte[] bytes = objectMapper.writeValueAsBytes(test); // 从字节流读取 com.example.blog.jacksontest.Test read = objectMapper.readValue(bytes, com.example.blog.jacksontest.Test.class); System.out.println(read); } /** * <P>JavaBean序列化XML</P> * 在序列化XML时,遇到了一个问题,也是Java8中LocalDateTime的问题,最后的解决办法是在字段上加上注解组局序列化 * @see com.example.blog.jacksontest.Test * 查过了一些资料,Springboot中没有xmlMapper的依赖,而且不可以用xmlMapper注册JacksonXmlModule对象 * @see JacksonXmlModule * 根据以上信息,大胆猜测需要在Springboot中配置XmlMapper的JavaBean,待实验 */ @Test public void javaBeanToXML() throws JsonProcessingException { com.example.blog.jacksontest.Test test = new com.example.blog.jacksontest.Test(); test.setLongId(1L); test.setStringTest(DATE_TIME_FORMAT); test.setIntTest(2); test.setDoubleTest(3.0); test.setShortTest((short) 44); test.setByteTest((byte) 1128); test.setCharTest('A'); ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("hello"); arrayList.add("world"); test.setListStringTest(arrayList); test.setLocalDateTimeTest(LocalDateTime.now()); test.setDateTest(new Date()); JacksonXmlModule jacksonXmlModule = new JacksonXmlModule(); jacksonXmlModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT))); jacksonXmlModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT))); xmlMapper.registerModule(jacksonXmlModule); String string = xmlMapper.writeValueAsString(test); System.out.println(string); } /** * <P>XML反序列化JavaBean</P> * 在反序列化XML时,遇到了一个问题,也是Java8中LocalDateTime的问题,最后的解决办法是在字段上加上注解组局序列化 * @see com.example.blog.jacksontest.Test * 查过了一些资料,Springboot中没有xmlMapper的依赖,而且不可以用xmlMapper注册JacksonXmlModule对象 * @see JacksonXmlModule * 根据以上信息,大胆猜测需要在Springboot中配置XmlMapper的JavaBean,待实验 */ @Test public void xmlToJavaBean() throws JsonProcessingException { String xml = "<Test><longId>1</longId><stringTest>yyyy-MM-dd HH:mm:ss</stringTest><intTest>2</intTest>" + "<doubleTest>3.0</doubleTest><shortTest>44</shortTest><byteTest>104</byteTest><charTest>A</charTest>" + "<listStringTest><listStringTest>hello</listStringTest><listStringTest>world</listStringTest></listStringTest>" + "<localDateTimeTest>2023-08-01 23:10:26</localDateTimeTest><dateTest>2023-08-01 15:10:26</dateTest></Test>\n"; com.example.blog.jacksontest.Test javaBean = JsonTest.xmlMapper.readValue(xml, new TypeReference<com.example.blog.jacksontest.Test>() { }); System.out.println(javaBean); Jackson2ObjectMapperBuilder xmlMapperBuild = new Jackson2ObjectMapperBuilder().createXmlMapper(true); } /** * <P>JSON串反序列化JavaBean</P> * * <p>LocalDateTime<p> * 当对象序列化的时候,需要自定义JavaTimeModule的LocalDateTime格式并且注册JavaTimeModule: * JavaTimeModule javaTimeModule = new JavaTimeModule(); * javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT))); * objectMapper.registerModule(javaTimeModule); * * <p>LocalDateTimeDate<p> * <p> * 此属性序列化于反序列化时,需要在此对象字段加上@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss"),不推荐在JavaTimeModule中定义和objectMapper设置 * 因为SimpleDateFormat是线程不安全的,但是ObjectMapper对象是现场安全的,这样会导致ObjectMapper也是不安全的,错误的如下 * SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); * objectMapper.setDateFormat(dateFormat); */ @Test public void deserializeToJavaBean() throws JsonProcessingException { String deserialized = "{\n" + " \"longId\" : 1,\n" + " \"stringTest\" : \"yyyy-MM-dd HH:mm:ss\",\n" + " \"intTest\" : 2,\n" + " \"doubleTest\" : 3.0,\n" + " \"shortTest\" : 44,\n" + " \"byteTest\" : 104,\n" + " \"charTest\" : \"A\",\n" + " \"listStringTest\" : [ \"hello\", \"world\" ],\n" + " \"localDateTimeTest\" : \"2023-08-01 19:24:02\",\n" + " \"dateTest\" : \"2023-08-01 11:24:02\"\n" + "}"; com.example.blog.jacksontest.Test deserializeResult = objectMapper.readValue(deserialized, com.example.blog.jacksontest.Test.class); System.out.println(deserializeResult); } /** * <P>JSON串反序列化Map集合</P> */ @Test public void deserializeToMap() throws JsonProcessingException { String serialized = "{\"longId\":1,\"stringTest\":\"yyyy-MM-dd HH:mm:ss\",\"intTest\":2," + "\"doubleTest\":3.0,\"shortTest\":-32768,\"byteTest\":104,\"charTest\":\"A\"," + "\"localDateTimeTest\":\"2023-08-31 22:26:43\",\"dateTest\":\"2023-07-31 14:26:43\"}"; Map<String, String> map = objectMapper.readValue(serialized, new TypeReference<>() { }); System.out.println(map); } /** * <P>JSON串反序列化List集合</P> * 注意: List的JSON串多了个中括号[] */ @Test public void deserializeToList() throws JsonProcessingException { String serialized = "[{\"longId\":1,\"stringTest\":\"yyyy-MM-dd HH:mm:ss\",\"intTest\":2," + "\"doubleTest\":3.0,\"shortTest\":-32768,\"byteTest\":104,\"charTest\":\"A\"," + "\"localDateTimeTest\":\"2023-08-31 22:26:43\",\"dateTest\":\"2023-07-31 14:26:43\"}]"; List<com.example.blog.jacksontest.Test> tests = objectMapper.readValue(serialized, new TypeReference<List<com.example.blog.jacksontest.Test>>() { }); System.out.println(tests); } /** * <P>JavaBean覆盖更新</P> * <p> * 对JavaBean字段属性的重写,如果后者有值,则用后者,没有则用前者, */ @Test public void javaBeanOverrideTest() throws JsonProcessingException { com.example.blog.jacksontest.Test Source = new com.example.blog.jacksontest.Test(); Source.setLongId(1L); Source.setStringTest(DATE_TIME_FORMAT); Source.setIntTest(1); Source.setDoubleTest(1.0); Source.setShortTest((short) 1); Source.setByteTest((byte) 1); Source.setLocalDateTimeTest(LocalDateTime.now()); Source.setDateTest(new Date()); com.example.blog.jacksontest.Test overrideField = new com.example.blog.jacksontest.Test(); overrideField.setLongId(2L); overrideField.setStringTest(DATE_TIME_FORMAT); overrideField.setIntTest(2); overrideField.setDoubleTest(2.0); overrideField.setShortTest((short) 2); overrideField.setByteTest((byte) 2); // 新增属性 overrideField.setCharTest('B'); overrideField.setLocalDateTimeTest(LocalDateTime.now()); overrideField.setDateTest(new Date()); com.example.blog.jacksontest.Test test = objectMapper.updateValue(Source, overrideField); System.out.println(test); } /** * <P>泛型的处理</P> */ @Test public void genericTest() throws JsonProcessingException { com.example.blog.jacksontest.Test test = new com.example.blog.jacksontest.Test(); test.setLongId(1L); test.setStringTest(DATE_TIME_FORMAT); test.setIntTest(2); test.setDoubleTest(3.0); test.setShortTest((short) 32768); test.setByteTest((byte) 1128); test.setCharTest('A'); test.setLocalDateTimeTest(LocalDateTime.now()); test.setDateTest(new Date()); // 数据封装返回类 Result<com.example.blog.jacksontest.Test> testResult = ResultBuilder.successResult(test); // 序列化返回结果 String genericResult = objectMapper.writeValueAsString(testResult); // 反序列化结果 Result<com.example.blog.jacksontest.Test> deserializerResult = objectMapper.readValue(genericResult, new TypeReference<Result<com.example.blog.jacksontest.Test>>() { }); System.out.println("带泛型的反序列化: " + deserializerResult); com.example.blog.jacksontest.Test data = deserializerResult.getData(); System.out.println("数据反序列化对象: " + data); } /** * <P>解析JSON字符串为JSON树模型</P> * 当JSON串数据类型比较多内容复杂时,则可使用JSON树模型来灵活的获取所需的字段内容,如下面的JSON串中,我们只需要listStringTest这个数组 * <p> * 在Jackson中提供了get、path、has等方法来获取或判断 */ @Test public void jsonTreeNode() throws JsonProcessingException { String jsonString = "{\n" + " \"longId\" : 1,\n" + " \"stringTest\" : \"yyyy-MM-dd HH:mm:ss\",\n" + " \"intTest\" : 2,\n" + " \"doubleTest\" : 3.0,\n" + " \"shortTest\" : 44,\n" + " \"byteTest\" : 104,\n" + " \"charTest\" : \"A\",\n" + " \"listStringTest\" : [ \"hello\", \"world\" ],\n" + " \"localDateTimeTest\" : \"2023-08-01 20:04:35\",\n" + " \"dateTest\" : \"2023-08-01 12:04:35\"\n" + "}"; JsonNode treeNode = objectMapper.readTree(jsonString); // 单独获取某个字段 JsonNode longId = treeNode.path("longId"); System.out.println(longId); // 获取数组内的数据 JsonNode listStringTest = treeNode.get("listStringTest"); for (JsonNode jsonNode : listStringTest) { System.out.println(jsonNode); } } /** * <P>jackson注解测试</P> * @see com.example.blog.jacksontest.JacksonAnnotationEntityTest */ @Test public void jacksonAnnotationTest() throws JsonProcessingException { JacksonAnnotationEntityTest jacksonAnnotationEntityTest = new JacksonAnnotationEntityTest(); jacksonAnnotationEntityTest.setLongId(1L); jacksonAnnotationEntityTest.setStringTest(DATE_TIME_FORMAT); jacksonAnnotationEntityTest.setIntTest(2); jacksonAnnotationEntityTest.setDoubleTest(3.0); jacksonAnnotationEntityTest.setShortTest((short) 44); jacksonAnnotationEntityTest.setByteTest((byte) 1128); jacksonAnnotationEntityTest.setCharTest('A'); ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("hello"); arrayList.add("world"); jacksonAnnotationEntityTest.setBooleanTest(true); jacksonAnnotationEntityTest.setListStringTest(arrayList); jacksonAnnotationEntityTest.setLocalDateTimeTest(LocalDateTime.now()); jacksonAnnotationEntityTest.setDateTest(new Date()); String string = objectMapper.writeValueAsString(jacksonAnnotationEntityTest); System.out.println(string); } }
注解测试
/** * <P>Jackson注解序列化测试</P> * @author unknown * @since 2023/08/01 03:40 * 更多注解请参考: https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations * <P> * JsonIgnoreProperties("Field1","Field2") * 多字段在序列化和反序列化时进行忽略,升级版的JsonIgnore * <P> * JsonIgnoreType * 在序列化和反序列化时,会忽略此类型,例如有一个demo类,类中有成员属性JacksonAnnotationEntityTest, * 那么在序列化和反序列化demo类时,将不会输出类中有成员属性JacksonAnnotationEntityTest * <P> * JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) * */ @Data @JsonIgnoreProperties({"doubleTest","shortTest"}) //@JsonIgnoreType @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class JacksonAnnotationEntityTest { private long longId; /** * <P</P> * JsonProperty("xxx") * 改变序列化后的字段名称,以括号内的名字取代原本字段名称 */ @JsonProperty("xxx") private String stringTest; /** * <P></P> * JsonIgnore * 此注解在序列化及反序列化的时候会忽略此字段 */ @JsonIgnore private int intTest; private double doubleTest; private boolean booleanTest; private short shortTest; private byte byteTest; private char charTest; private List<String> listStringTest; private LocalDateTime localDateTimeTest; private Date dateTest; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端