写点什么

jackson 学习之三:常用 API 操作

作者:程序员欣宸
  • 2022 年 4 月 08 日
  • 本文字数:7049 字

    阅读完需:约 23 分钟

jackson学习之三:常用API操作

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos


源码下载

  1. 如果您不想编码,可以在 GitHub 下载所有源码,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):



  1. 这个 git 项目中有多个文件夹,本章的应用在 jacksondemo 文件夹下,如下图红框所示:


本篇概览

  • 本文是《jackson 学习》系列的第三篇,前面咱们学习了 jackson 的低阶 API,知道了底层原理,本篇开始学习平时最常用的基本功能,涉及内容如下:

1. 体验最常用的操作,内容如下图所示:


2. 介绍常用的可配置属性,以便按需要来设置;

3. 接下来进入快速浏览的环节,咱们一起先把各个 API 过一遍;

单个对象序列化

先看常用的序列化 API:

  1. 对象转字符串:

String jsonStr = mapper.writeValueAsString(twitterEntry);
复制代码


  1. 对象转文件:

mapper.writeValue(new File("twitter.json"), twitterEntry);
复制代码


  1. 对象转 byte 数组:

byte[] array = mapper.writeValueAsBytes(twitterEntry);
复制代码


单个对象反序列化

  1. 字符串转对象:

TwitterEntry tFromStr = mapper.readValue(objectJsonStr, TwitterEntry.class);
复制代码


  1. 文件转对象:

TwitterEntry tFromFile = mapper.readValue(new File("twitter.json"), TwitterEntry.class);
复制代码


  1. byte 数组转对象:

TwitterEntry tFromBytes = mapper.readValue(array, TwitterEntry.class);
复制代码


  1. 字符串网络地址转对象:

String testJsonDataUrl = "https://raw.githubusercontent.com/zq2599/blog_demos/master/files/twitteer_message.json";
TwitterEntry tFromUrl = mapper.readValue(new URL(testJsonDataUrl), TwitterEntry.class);
复制代码


集合序列化

  1. HashMap 转字符串:

String mapJsonStr = mapper.writeValueAsString(map);
复制代码

集合反序列化

  1. 字符串转 HashMap:

Map<String, Object> mapFromStr = mapper.readValue(mapJsonStr, new TypeReference<Map<String, Object>>() {});
复制代码

JsonNode

  1. 如果您不想使用 XXX.class 来做反序列化,也能使用 JsonNode 来操作:

JsonNode jsonNode = mapper.readTree(mapJsonStr);String name = jsonNode.get("name").asText();int age = jsonNode.get("age").asInt();String city = jsonNode.get("addr").get("city").asText();String street = jsonNode.get("addr").get("street").asText();
复制代码


时间字段格式化

  1. 对于 Date 字段,默认的反序列化是时间戳,可以修改配置:

mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"));dateMapStr = mapper.writeValueAsString(dateMap);
复制代码

JSON 数组的反序列化

  • 假设 jsonArrayStr 是个 json 数组格式的字符串:

  1. JSON 数组转对象数组:

TwitterEntry[] twitterEntryArray = mapper.readValue(jsonArrayStr, TwitterEntry[].class);
复制代码


  1. JSON 数组转对象集合(ArrayList):

List<TwitterEntry> twitterEntryList = mapper.readValue(jsonArrayStr, new TypeReference<List<TwitterEntry>>() {});
复制代码


完整代码

  1. 上述所有常用 API 用法的完整代码如下:

package com.bolingcavalry.jacksondemo.databind;
import com.bolingcavalry.jacksondemo.beans.TwitterEntry;import com.fasterxml.jackson.core.type.TypeReference;import com.fasterxml.jackson.databind.JsonNode;import com.fasterxml.jackson.databind.ObjectMapper;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.io.File;import java.net.URL;import java.text.SimpleDateFormat;import java.util.*;
public class SimpleDemo {
private static final Logger logger = LoggerFactory.getLogger(SimpleDemo.class);
public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper();
logger.info("以下是序列化操作");
// 对象 -> 字符串 TwitterEntry twitterEntry = new TwitterEntry(); twitterEntry.setId(123456L); twitterEntry.setFromUserId(101); twitterEntry.setToUserId(102); twitterEntry.setText("this is a message for serializer test"); twitterEntry.setLanguageCode("zh");
String jsonStr = mapper.writeValueAsString(twitterEntry); logger.info("序列化的字符串:{}", jsonStr);
// 对象 -> 文件 mapper.writeValue(new File("twitter.json"), twitterEntry);
// 对象 -> byte数组 byte[] array = mapper.writeValueAsBytes(twitterEntry);
logger.info("\n\n以下是反序列化操作");
// 字符串 -> 对象 String objectJsonStr = "{\n" + " \"id\":1125687077,\n" + " \"text\":\"@stroughtonsmith You need to add a \\\"Favourites\\\" tab to TC/iPhone. Like what TwitterFon did. I can't WAIT for your Twitter App!! :) Any ETA?\",\n" + " \"fromUserId\":855523, \n" + " \"toUserId\":815309,\n" + " \"languageCode\":\"en\"\n" + "}";

TwitterEntry tFromStr = mapper.readValue(objectJsonStr, TwitterEntry.class); logger.info("从字符串反序列化的对象:{}", tFromStr);
// 文件 -> 对象 TwitterEntry tFromFile = mapper.readValue(new File("twitter.json"), TwitterEntry.class); logger.info("从文件反序列化的对象:{}", tFromStr);
// byte数组 -> 对象 TwitterEntry tFromBytes = mapper.readValue(array, TwitterEntry.class); logger.info("从byte数组反序列化的对象:{}", tFromBytes);
// 字符串网络地址 -> 对象 String testJsonDataUrl = "https://raw.githubusercontent.com/zq2599/blog_demos/master/files/twitteer_message.json";
TwitterEntry tFromUrl = mapper.readValue(new URL(testJsonDataUrl), TwitterEntry.class); logger.info("从网络地址反序列化的对象:{}", tFromUrl);

logger.info("\n\n以下是集合序列化操作");
Map<String, Object> map = new HashMap<>(); map.put("name", "tom"); map.put("age", 11);
Map<String, String> addr = new HashMap<>(); addr.put("city","深圳"); addr.put("street", "粤海");
map.put("addr", addr);
String mapJsonStr = mapper.writeValueAsString(map); logger.info("HashMap序列化的字符串:{}", mapJsonStr);
logger.info("\n\n以下是集合反序列化操作"); Map<String, Object> mapFromStr = mapper.readValue(mapJsonStr, new TypeReference<Map<String, Object>>() {}); logger.info("从字符串反序列化的HashMap对象:{}", mapFromStr);
// JsonNode类型操作 JsonNode jsonNode = mapper.readTree(mapJsonStr); String name = jsonNode.get("name").asText(); int age = jsonNode.get("age").asInt(); String city = jsonNode.get("addr").get("city").asText(); String street = jsonNode.get("addr").get("street").asText();
logger.info("用JsonNode对象和API反序列化得到的数:name[{}]、age[{}]、city[{}]、street[{}]", name, age, city, street);
// 时间类型格式
Map<String, Object> dateMap = new HashMap<>(); dateMap.put("today", new Date());
String dateMapStr = mapper.writeValueAsString(dateMap); logger.info("默认的时间序列化:{}", dateMapStr);
// 设置时间格式 mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")); dateMapStr = mapper.writeValueAsString(dateMap); logger.info("自定义的时间序列化:{}", dateMapStr);
System.out.println(objectJsonStr);
// json数组 String jsonArrayStr = "[{\n" + " \"id\":1,\n" + " \"text\":\"text1\",\n" + " \"fromUserId\":11, \n" + " \"toUserId\":111,\n" + " \"languageCode\":\"en\"\n" + "},\n" + "{\n" + " \"id\":2,\n" + " \"text\":\"text2\",\n" + " \"fromUserId\":22, \n" + " \"toUserId\":222,\n" + " \"languageCode\":\"zh\"\n" + "},\n" + "{\n" + " \"id\":3,\n" + " \"text\":\"text3\",\n" + " \"fromUserId\":33, \n" + " \"toUserId\":333,\n" + " \"languageCode\":\"en\"\n" + "}]";
// json数组 -> 对象数组 TwitterEntry[] twitterEntryArray = mapper.readValue(jsonArrayStr, TwitterEntry[].class); logger.info("json数组反序列化成对象数组:{}", Arrays.toString(twitterEntryArray));
// json数组 -> 对象集合 List<TwitterEntry> twitterEntryList = mapper.readValue(jsonArrayStr, new TypeReference<List<TwitterEntry>>() {}); logger.info("json数组反序列化成对象集合:{}", twitterEntryList); }}
复制代码
  1. 执行结果如下:

C:\jdk\bin\java.exe -javaagent:C:\sofware\JetBrains\IntelliJIDEA\lib\idea_rt.jar=64570:C:\sofware\JetBrains\IntelliJIDEA\bin -Dfile.encoding=UTF-8 -classpath C:\jdk\jre\lib\charsets.jar;C:\jdk\jre\lib\deploy.jar;C:\jdk\jre\lib\ext\access-bridge-64.jar;C:\jdk\jre\lib\ext\cldrdata.jar;C:\jdk\jre\lib\ext\dnsns.jar;C:\jdk\jre\lib\ext\jaccess.jar;C:\jdk\jre\lib\ext\jfxrt.jar;C:\jdk\jre\lib\ext\localedata.jar;C:\jdk\jre\lib\ext\nashorn.jar;C:\jdk\jre\lib\ext\sunec.jar;C:\jdk\jre\lib\ext\sunjce_provider.jar;C:\jdk\jre\lib\ext\sunmscapi.jar;C:\jdk\jre\lib\ext\sunpkcs11.jar;C:\jdk\jre\lib\ext\zipfs.jar;C:\jdk\jre\lib\javaws.jar;C:\jdk\jre\lib\jce.jar;C:\jdk\jre\lib\jfr.jar;C:\jdk\jre\lib\jfxswt.jar;C:\jdk\jre\lib\jsse.jar;C:\jdk\jre\lib\management-agent.jar;C:\jdk\jre\lib\plugin.jar;C:\jdk\jre\lib\resources.jar;C:\jdk\jre\lib\rt.jar;D:\github\blog_demos\jacksondemo\databind\target\classes;C:\Users\12167\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.11.0\jackson-databind-2.11.0.jar;C:\Users\12167\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.11.0\jackson-annotations-2.11.0.jar;C:\Users\12167\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.11.0\jackson-core-2.11.0.jar;C:\Users\12167\.m2\repository\org\slf4j\slf4j-log4j12\1.7.25\slf4j-log4j12-1.7.25.jar;C:\Users\12167\.m2\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;C:\Users\12167\.m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;C:\Users\12167\.m2\repository\commons-io\commons-io\2.7\commons-io-2.7.jar;C:\Users\12167\.m2\repository\org\apache\commons\commons-lang3\3.10\commons-lang3-3.10.jar;D:\github\blog_demos\jacksondemo\beans\target\classes com.bolingcavalry.jacksondemo.databind.SimpleDemo2020-08-28 07:53:01 INFO  SimpleDemo:27 - 以下是序列化操作2020-08-28 07:53:01 INFO  SimpleDemo:38 - 序列化的字符串:{"id":123456,"text":"this is a message for serializer test","fromUserId":101,"toUserId":102,"languageCode":"zh"}2020-08-28 07:53:01 INFO  SimpleDemo:47 - 
以下是反序列化操作2020-08-28 07:53:01 INFO SimpleDemo:60 - 从字符串反序列化的对象:[Tweet, id: 1125687077, text='@stroughtonsmith You need to add a "Favourites" tab to TC/iPhone. Like what TwitterFon did. I can't WAIT for your Twitter App!! :) Any ETA?', from: 855523, to: 815309, lang: en]2020-08-28 07:53:01 INFO SimpleDemo:64 - 从文件反序列化的对象:[Tweet, id: 1125687077, text='@stroughtonsmith You need to add a "Favourites" tab to TC/iPhone. Like what TwitterFon did. I can't WAIT for your Twitter App!! :) Any ETA?', from: 855523, to: 815309, lang: en]2020-08-28 07:53:01 INFO SimpleDemo:68 - 从byte数组反序列化的对象:[Tweet, id: 123456, text='this is a message for serializer test', from: 101, to: 102, lang: zh]2020-08-28 07:53:04 INFO SimpleDemo:74 - 从网络地址反序列化的对象:[Tweet, id: 112233445566, text='this is a message from zq2599's github', from: 201, to: 202, lang: en]2020-08-28 07:53:04 INFO SimpleDemo:77 -
以下是集合序列化操作2020-08-28 07:53:04 INFO SimpleDemo:90 - HashMap序列化的字符串:{"name":"tom","addr":{"city":"深圳","street":"粤海"},"age":11}2020-08-28 07:53:04 INFO SimpleDemo:92 -
以下是集合反序列化操作2020-08-28 07:53:04 INFO SimpleDemo:94 - 从字符串反序列化的HashMap对象:{name=tom, addr={city=深圳, street=粤海}, age=11}2020-08-28 07:53:04 INFO SimpleDemo:103 - 用JsonNode对象和API反序列化得到的数:name[tom]、age[11]、city[深圳]、street[粤海]2020-08-28 07:53:04 INFO SimpleDemo:111 - 默认的时间序列化:{"today":1598572384838}2020-08-28 07:53:04 INFO SimpleDemo:116 - 自定义的时间序列化:{"today":"2020-08-28 07:53:04"}{ "id":1125687077, "text":"@stroughtonsmith You need to add a \"Favourites\" tab to TC/iPhone. Like what TwitterFon did. I can't WAIT for your Twitter App!! :) Any ETA?", "fromUserId":855523, "toUserId":815309, "languageCode":"en"}2020-08-28 07:53:04 INFO SimpleDemo:145 - json数组反序列化成对象数组:[[Tweet, id: 1, text='text1', from: 11, to: 111, lang: en], [Tweet, id: 2, text='text2', from: 22, to: 222, lang: zh], [Tweet, id: 3, text='text3', from: 33, to: 333, lang: en]]2020-08-28 07:53:04 INFO SimpleDemo:149 - json数组反序列化成对象集合:[[Tweet, id: 1, text='text1', from: 11, to: 111, lang: en], [Tweet, id: 2, text='text2', from: 22, to: 222, lang: zh], [Tweet, id: 3, text='text3', from: 33, to: 333, lang: en]]
Process finished with exit code 0
复制代码


  1. 还会产生名为 twitter.json 的文件,内容如下:

{"id":123456,"text":"this is a message for serializer test","fromUserId":101,"toUserId":102,"languageCode":"zh"}
复制代码


常用配置

  • 下面是平时可能用到的自定义配置项目:

  1. 序列化结果格式化:

mapper.enable(SerializationFeature.INDENT_OUTPUT);
复制代码
  1. 空对象不要抛出异常:

mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
复制代码


  1. Date、Calendar 等序列化为时间格式的字符串(如果不执行以下设置,就会序列化成时间戳格式):

mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
复制代码


  1. 反序列化时,遇到未知属性不要抛出异常:

mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
复制代码
  1. 反序列化时,空字符串对于的实例属性为 null:

mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
复制代码


  1. 允许 C 和 C++样式注释:

mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
复制代码


  1. 允许字段名没有引号(可以进一步减小 json 体积):

mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
复制代码


  1. 允许单引号:

mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
复制代码

特殊配置:在 json 对象最外层再包裹一层

  1. 最后要说的是个特殊配置,先来看看正常情况一个普通的序列化结果:

{  "id" : 1,  "text" : "aabbcc",  "fromUserId" : 456,  "toUserId" : 0,  "languageCode" : "zh"}
复制代码


  1. 接下来咱们做两件事,首先,是给上述 json 对应的实例类添加一个注解,如下图红框:

  2. 其次,执行以下配置:

mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
复制代码


  1. 然后再次执行 TwitterEntry 实例的序列化,得到的结果如下,可见和之前的序列化结果相比,之前的整个 json 都变成了一个 value,此 value 对应的 key 就是注解 JsonRootName 的 value 属性:

{  "aaa" : {    "id" : 1,    "text" : "aabbcc",    "fromUserId" : 456,    "toUserId" : 0,    "languageCode" : "zh"  }}
复制代码
  • 至此,开发中常用的 API 和配置都已经介绍完成,希望能给您带来一些参考,接下来的章节,咱们一起去了解另一个常用操作:jackson 注解

欢迎关注 InfoQ:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

发布于: 2022 年 04 月 08 日阅读数: 14
用户头像

搜索"程序员欣宸",一起畅游Java宇宙 2018.04.19 加入

前腾讯、前阿里员工,从事Java后台工作,对Docker和Kubernetes充满热爱,所有文章均为作者原创,个人Github:https://github.com/zq2599/blog_demos

评论

发布
暂无评论
jackson学习之三:常用API操作_四月月更_程序员欣宸_InfoQ写作平台