Jackson

简介

依赖

  • jackson-core
  • jackson- annotations
  • jackson-databind

其中 jackson-databind 内部依赖了 jackson-annotations 与 jackson-core,所以 Maven 应用时,只要导入 databind 一个,则同时也导入了 annotations 与 core 依赖。
核心模块
Streaming(jackson-core):低阶API库,提供流式解析工具JsonParser,流式生成工具JsonGenerator;
Annotations(jackson-annotations):jackson注解;
Databind (jackson-databind):基于java对象的序列化、反序列化能力,需要前面两个模块的支持才能实现;

Jackson常用的类

  • JsonFactory:这个类是Jackson主要的工厂方法,主要用于配置和构建解析器(JsonParser)和生成器(如JsonGenerator),这个工厂实例是线程安全的,如果有配置的话,可以重复使用。
  • JsonGenerator:这个类主要是用来生成Json格式的内容的,我们可以使用JsonFactory 的方法生成一个实例。
  • JsonParser:这个主要是用来读取Json格式的内容,并且完成解析操作的,我们可以使用JsonFactory的方法生成一个实例。
  • ObjectMapper:这个类提供了Java对象和Json之间的转化,主要通过JsonParser和JsonGenerator实例来完成实际的对Json数据的读写操作。

    Jackson-core

  1. jackson-core为一个低阶API库,提供流式解析工具JsonParser,流式生成工具JsonGenerator
  2. 在日常的序列化和反序列化处理中,最常用的是jackson-annotations和jackson-databind,而jackson-core由于它提供的API过于基础,我们大多数情况下是用不上的;
  3. 尽管jackson-databind负责序列化和反序列化处理,但它的底层实现是调用了jackson-core的API;

JsonGenerator是定义公共API编写的Json内容的基类,使用JsonFactory实例的工厂方法创建实例。
JsonGenerator的使用案例如下所示:

  1. package test;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.io.PrintWriter;
  5. import org.codehaus.jackson.JsonGenerationException;
  6. import org.codehaus.jackson.JsonGenerator;
  7. import org.codehaus.jackson.map.ObjectMapper;
  8. public class JsonGeneratorTest {
  9. public static void main(String[] args) throws JsonGenerationException, IOException {
  10. String ret = "";
  11. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  12. ObjectMapper mapper = new ObjectMapper();
  13. JsonGenerator jg = mapper.getJsonFactory().createJsonGenerator(new PrintWriter(bos));
  14. jg.writeStartObject();
  15. jg.writeStringField("name", "zhaokaiqiang");
  16. jg.writeNumberField("age", 22);
  17. jg.writeObjectField("sex", "man");
  18. jg.writeArrayFieldStart("likes");
  19. jg.writeString("apple");
  20. jg.writeString("banner");
  21. jg.writeStartObject();
  22. jg.writeNumberField("index",1);
  23. jg.writeStringField("color","red");
  24. jg.writeEndObject();
  25. jg.writeStartObject();
  26. jg.writeNumberField("index",2);
  27. jg.writeStringField("color","green");
  28. jg.writeEndObject();
  29. jg.writeEndArray();
  30. jg.writeEndObject();
  31. jg.flush();
  32. jg.close();
  33. ret = bos.toString();
  34. bos.close();
  35. System.out.println(ret);
  36. }
  37. }

Jackson - 图1

ObjectMapper

一)、从JSON中获取Java对象

1.简单示例:

从Json字符串中解析数据并封装到实体类当中
readValue绑定实体类和json字符串,用于进行读取解析封装,返回一个实体类

  1. public class Car {
  2. private String brand = null;
  3. private int doors = 0;
  4. public String getBrand() { return this.brand; }
  5. public void setBrand(String brand){ this.brand = brand;}
  6. public int getDoors() { return this.doors; }
  7. public void setDoors (int doors) { this.doors = doors; }
  8. }
  1. public class testObjectMapper {
  2. @Test
  3. public void test1(){
  4. ObjectMapper objectMapper= new ObjectMapper();
  5. String carJson="{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
  6. Car car;
  7. {
  8. try {
  9. car = objectMapper.readValue(carJson,Car.class);
  10. System.out.println("car brand"+ car.getBrand());
  11. System.out.println("car doors"+ car.getDoors());
  12. } catch (IOException e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. }
  1. {
  2. "brand":"Mercedes",
  3. "doors":"5"
  4. }

2.ObjectMapper如何匹配JSON对象的字段和Java对象的属性

默认情况下,Jackson通过将JSON字段的名称与Java对象中的getter和setter方法进行匹配,将JSON对象的字段映射到Java对象中的属性。 Jackson删除了getter和setter方法名称的“ get”和“ set”部分,并将其余名称的第一个字符转换为小写。

3.Json字符串->Java对象

从JSON字符串读取Java对象非常容易。 上面已经有了一个示例——JSON字符串作为第一个参数传递给ObjectMapper的readValue()方法。 这是另一个简单的示例:

  1. ObjectMapper objectMapper = new ObjectMapper();
  2. String carJson =
  3. "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
  4. Car car = objectMapper.readValue(carJson, Car.class);

3.Json字符输入流->Java对象

通过Reader实例加载的JSON中读取对象

  1. ObjectMapper objectMapper = new ObjectMapper();
  2. String carJson =
  3. "{ \"brand\" : \"Mercedes\", \"doors\" : 4 }";
  4. Reader reader = new StringReader(carJson);
  5. Car car = objectMapper.readValue(reader, Car.class);

4.JSON文件->Java对象

从文件读取JSON当然可以通过FileReader(而不是StringReader)来完成,也可以通过File对象来完成。

  1. @Test
  2. public void testFile(){
  3. ObjectMapper objectMapper=new ObjectMapper();
  4. File file=new File("D:\\learn_software\\program_file\\IDEAProgject\\jackson\\src\\main\\java\\com\\fischer\\data\\car.json");
  5. try {
  6. Car car = objectMapper.readValue(file, Car.class);
  7. System.out.println(car);
  8. } catch (IOException e) {
  9. e.printStackTrace();
  10. }
  11. }
  1. Car{brand='Mercedes', doors=5}//输出结果

5.JSON via URL -> Java对象

  1. ObjectMapper objectMapper = new ObjectMapper();
  2. URL url = new URL("file:data/car.json");
  3. Car car = objectMapper.readValue(url, Car.class);

示例使用文件URL,也可以使用HTTP URL(类似于http://jenkov.com/some-data.json)。

6.JSON数组字符串->Java对象数组

Jackson ObjectMapper也可以从JSON数组字符串读取对象数组。 这是从JSON数组字符串读取对象数组的示例:

  • 注意readValue中指定为数组类型的Car[]

    1. @Test
    2. public void testArray(){
    3. String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
    4. ObjectMapper objectMapper=new ObjectMapper();
    5. try {
    6. for (Car car : objectMapper.readValue(jsonArray, Car[].class)) {
    7. System.out.println(car);
    8. }
    9. } catch (IOException e) {
    10. e.printStackTrace();
    11. }
    12. }

    7.JSON数组字符串->List

  • TypeReference用于在反序列化时,将数据封装成泛型对象

    • 泛型中指定要封装成的对象,如TypeReference>,或TypeReference
    • 不使用TperReference:

      1. String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
      2. ObjectMapper objectMapper=new ObjectMapper();
      3. List list = objectMapper.readValue(jsonArray, List.class);
      1. {brand='ford', doors=0},{brand='Fiat', doors=0}
    • 使用TypeReference(具体代码如下)

      1. Car{brand='ford', doors=0},Car{brand='Fiat', doors=0}
      1. @Test
      2. public void testList(){
      3. String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
      4. ObjectMapper objectMapper=new ObjectMapper();
      5. try {
      6. for (Object o : (List) objectMapper.readValue(jsonArray, new TypeReference<List<Car>>() {
      7. })) {
      8. System.out.println(o);
      9. }
      10. } catch (IOException e) {
      11. e.printStackTrace();
      12. }
      13. }

      8.JSON字符串->Map

      与List同理,借助TypeReference

      1. String jsonObject = "{\"brand\":\"ford\", \"doors\":5}";
      2. ObjectMapper objectMapper = new ObjectMapper();
      3. Map<String, Object> jsonMap = objectMapper.readValue(jsonObject,
      4. new TypeReference<Map<String,Object>>(){});

      9.忽略未知JSON字段

      有时候,与要从JSON读取的Java对象相比,JSON中的字段更多。 默认情况下,Jackson在这种情况下会抛出异常,报不知道XYZ字段异常,因为在Java对象中找不到该字段。
      但是,有时应该允许JSON中的字段多于相应的Java对象中的字段。 例如,要从REST服务解析JSON,而该REST服务包含的数据远远超出所需的。 在这种情况下,可以使用Jackson配置忽略这些额外的字段。 以下是配置Jackson ObjectMapper忽略未知字段的示例:

      1. objectMapper.configure(
      2. DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
  • 日后研究研究是否可以在springboot的配置文件中进行设置:

    • Springboot中DeserializationFeature.XXX对应的关键词为deserialization.XXX
    • 在Springboot当中,对应的操作为:
      1. jackson:
      2. deserialization.FAIL_ON_UNKNOWN_PROPERTIES: false

      10.不允许基本类型为null

      如果JSON字符串包含其值设置为null的字段(对于在相应的Java对象中是基本数据类型(int,long,float,double等)的字段),Jackson ObjectMapper默认会处理基本数据类型为null的情况,如:int类型会默认赋值为0,字符串类型则为null我们可以可以将Jackson ObjectMapper默认配置为失效,这样基本数据为null就会转换失败
      1. objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
      1. @Test
      2. public void testNull(){
      3. String json="{ \"brand\":null, \"doors\":null }";
      4. ObjectMapper objectMapper=new ObjectMapper();
      5. objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
      6. try {
      7. Car car = objectMapper.readValue(json, Car.class);
      8. System.out.println(car);
      9. } catch (IOException e) {
      10. e.printStackTrace();
      11. }
      12. }
      得到以下报错:
      Jackson - 图2

      11.自定义反序列化

      暂时不大懂,日后用到了进一步研究
      有时,可能希望以不同于Jackson ObjectMapper缺省方式的方式将JSON字符串读入Java对象。 可以将自定义反序列化器添加到ObjectMapper,可以按需要执行反序列化。
      这是在Jackson的ObjectMapper中注册和使用自定义反序列化器的方式:
      1. String json = "{ \"brand\" : \"Ford\", \"doors\" : 6 }";
      2. SimpleModule module =
      3. new SimpleModule("CarDeserializer", new Version(3, 1, 8, null, null, null));
      4. module.addDeserializer(Car.class, new CarDeserializer(Car.class));
      5. ObjectMapper mapper = new ObjectMapper();
      6. mapper.registerModule(module);
      7. Car car = mapper.readValue(json, Car.class);
      自定义反序列化器CarDeserializer类
      1. public class CarDeserializer extends StdDeserializer<Car> {
      2. public CarDeserializer(Class<?> vc) {
      3. super(vc);
      4. }
      5. @Override
      6. public Car deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException {
      7. Car car = new Car();
      8. while(!parser.isClosed()){
      9. JsonToken jsonToken = parser.nextToken();
      10. if(JsonToken.FIELD_NAME.equals(jsonToken)){
      11. String fieldName = parser.getCurrentName();
      12. System.out.println(fieldName);
      13. jsonToken = parser.nextToken();
      14. if("brand".equals(fieldName)){
      15. car.setBrand(parser.getValueAsString());
      16. } else if ("doors".equals(fieldName)){
      17. car.setDoors(parser.getValueAsInt());
      18. }
      19. }
      20. }
      21. return car;
      22. }
      23. }

      二)、将对象写入JSON

      1.Java对象->JSON

      Jackson ObjectMapper也可以用于从对象生成JSON。 可以使用以下方法之一进行操作:
  • writeValue()

  • writeValueAsString()
  • writeValueAsBytes()

通过Car生成JSON:

  1. @Test
  2. public void testWrite(){
  3. ObjectMapper objectMapper=new ObjectMapper();
  4. Car car=new Car();
  5. car.setBrand("Tesla");
  6. car.setDoors(4);
  7. try {
  8. objectMapper.writeValue(new FileOutputStream("output-2.json"),car);
  9. } catch (IOException e) {
  10. e.printStackTrace();
  11. }

调用ObjectMapper的writeValue()方法,该方法将Car对象转换为JSON并将其写入给定的FileOutputStream,最后写入一个文件当中
ObjectMapper的writeValueAsString()和writeValueAsBytes()都从一个对象生成JSON,并将生成的JSON作为String或字节数组返回。 示例如下:

  1. @Test
  2. public void testWriteString() {
  3. ObjectMapper objectMapper = new ObjectMapper();
  4. Car car = new Car();
  5. car.setBrand("Tesla");
  6. car.setDoors(4);
  7. try {
  8. String s = objectMapper.writeValueAsString(car);
  9. System.out.println(s);
  10. } catch (IOException e) {
  11. e.printStackTrace();
  12. }
  13. }
  1. {"brand":"Tesla","doors":4}

2.自定义序列化

有时,想要将Java对象序列化为JSON的方式与使用Jackson的默认方式不同。 例如,可能想要在JSON中使用与Java对象中不同的字段名称,或者希望完全省略某些字段。
Jackson可以在ObjectMapper上设置自定义序列化器。 该序列化器已为某个类注册,然后在每次要求ObjectMapper序列化Car对象时将调用该序列化器。
这是为Car类注册自定义序列化器的示例:

  1. CarSerializer carSerializer = new CarSerializer(Car.class);
  2. ObjectMapper objectMapper = new ObjectMapper();
  3. SimpleModule module =
  4. new SimpleModule("CarSerializer", new Version(2, 1, 3, null, null, null));
  5. module.addSerializer(Car.class, carSerializer);
  6. objectMapper.registerModule(module);
  7. Car car = new Car();
  8. car.setBrand("Mercedes");
  9. car.setDoors(5);
  10. String carJson = objectMapper.writeValueAsString(car);

自定义序列化器CarSerializer类:

  1. public class CarSerializer extends StdSerializer<Car> {
  2. protected CarSerializer(Class<Car> t) {
  3. super(t);
  4. }
  5. public void serialize(Car car, JsonGenerator jsonGenerator,
  6. SerializerProvider serializerProvider)
  7. throws IOException {
  8. jsonGenerator.writeStartObject();
  9. jsonGenerator.writeStringField("producer", car.getBrand());
  10. jsonGenerator.writeNumberField("doorCount", car.getDoors());
  11. jsonGenerator.writeEndObject();
  12. }
  13. }

三)、Jackson日期转化

默认情况下,Jackson会将java.util.Date对象序列化为其long型的值,该值是自1970年1月1日以来的毫秒数。但是,Jackson还支持将日期格式化为字符串。
默认的Jackson日期格式,该格式将Date序列化为自1970年1月1日以来的毫秒数(long类型)。
日期pojo:

  1. public class Transaction {
  2. private String type = null;
  3. private Date date = null;
  4. }
  1. @Test
  2. public void testDate(){
  3. Transaction transaction=new Transaction("transfer",new Date());
  4. ObjectMapper objectMapper=new ObjectMapper();
  5. try {
  6. String s = objectMapper.writeValueAsString(transaction);
  7. System.out.println(s);
  8. } catch (JsonProcessingException e) {
  9. e.printStackTrace();
  10. }
  11. }
  1. {"type":"transfer","date":1646377981781}//结果

设置Jackson日期格式

  1. @Test
  2. public void testDate(){
  3. Transaction transaction=new Transaction("transfer",new Date());
  4. ObjectMapper objectMapper=new ObjectMapper();
  5. try {
  6. SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
  7. objectMapper.setDateFormat(dateFormat);
  8. String s = objectMapper.writeValueAsString(transaction);
  9. System.out.println(s);
  10. } catch (JsonProcessingException e) {
  11. e.printStackTrace();
  12. }
  13. }
  1. {"type":"transfer","date":"2022-03-04"}

四)、Jackson JSON树模型

Jackson具有内置的树模型,可用于表示JSON对象。

  • 如果不知道接收到的JSON的格式,或者由于某种原因而不能(或者只是不想)创建一个类来表示它,那么就要用到Jackson的树模型。
  • 如果需要在使用或转化JSON之前对其进行操作,也需要被用到Jackson树模型。

    1.快速入门

    在原本传入实体类.class的位置变为传入JsonNode.class,即可将json字符串解析为JsonNode对象

    1. @Test
    2. public void testquickStart(){
    3. String carJson =
    4. "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
    5. ObjectMapper objectMapper=new ObjectMapper();
    6. try {
    7. JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);
    8. System.out.println(jsonNode.toString());
    9. } catch (IOException e) {
    10. e.printStackTrace();
    11. }
    12. }

    ObjectMapper类还具有一个特殊的readTree()方法,该方法返回JsonNode。 这是使用ObjectMapper readTree()方法将JSON解析为JsonNode的示例:

    1. String carJson =
    2. "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
    3. ObjectMapper objectMapper = new ObjectMapper();
    4. try {
    5. JsonNode jsonNode = objectMapper.readTree(carJson);
    6. } catch (IOException e) {
    7. e.printStackTrace();
    8. }

    2. Jackson JsonNode类

    通过JsonNode类,可以以非常灵活和动态的方式将JSON作为Java对象导航。这里了解一些如何使用它的基础知识。
    将JSON解析为JsonNode(或JsonNode实例树)后,就可以浏览JsonNode树模型:

  • 解析JSON字段(String,int)

  • 解析数组
  • 解析嵌套类型

    1. {
    2. "brand":"Mercedes",
    3. "doors":5,
    4. "owners":["John","Jack","Jill"],
    5. "nestedObject":{"field":"value"}
    6. }
    1. @Test
    2. public void testJsonNode(){
    3. String carJson =
    4. "{ \"brand\" : \"Mercedes\", \"doors\" : 5," +
    5. " \"owners\" : [\"John\", \"Jack\", \"Jill\"]," +
    6. " \"nestedObject\" : { \"field\" : \"value\" } }";
    7. ObjectMapper objectMapper = new ObjectMapper();
    8. try {
    9. //字符串类型字段
    10. JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);
    11. JsonNode brandNode = jsonNode.get("brand");
    12. String s = brandNode.asText();
    13. System.out.println("brand -> "+s);
    14. //int类型字段
    15. JsonNode doors = jsonNode.get("doors");
    16. int i = doors.asInt();
    17. System.out.println("doors -> "+i);
    18. //数组类型
    19. JsonNode owners = jsonNode.get("owners");
    20. for (JsonNode owner : owners) {
    21. String text = owner.asText();
    22. System.out.print(text+" ");
    23. }
    24. System.out.println("");
    25. //嵌套类型
    26. JsonNode nestedObject = jsonNode.get("nestedObject");
    27. JsonNode field = nestedObject.get("field");
    28. String asText = field.asText();
    29. System.out.println("field "+ asText);
    30. } catch (IOException e) {
    31. e.printStackTrace();
    32. }
    33. }

    解析结果:
    Jackson - 图3

    3.Java对象->JsonNode

    1. ObjectMapper objectMapper = new ObjectMapper();
    2. Car car = new Car();
    3. car.brand = "Cadillac";
    4. car.doors = 4;
    5. JsonNode carJsonNode = objectMapper.valueToTree(car);

    4.JsonNode-> Java对象

    1. ##ObjectMapper objectMapper = new ObjectMapper();
    2. String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
    3. JsonNode carJsonNode = objectMapper.readTree(carJson);
    4. Car car = objectMapper.treeToValue(carJsonNode);

    JsonNode

    Jackson JsonNode类com.fasterxml.jackson.databind.JsonNode是Jackson的JSON树形模型(对象图模型)。 Jackson可以将JSON读取到JsonNode实例中,然后将JsonNode写入JSON。 因此,这一节将说明如何将JSON反序列化为JsonNode以及将JsonNode序列化为JSON

    1.JsonNode vs ObjectNode

    Jackson JsonNode类是不可变的。 这意味着,实际上不能直接构建JsonNode实例的对象图。 而是创建JsonNode子类ObjectNode的对象图。 作为JsonNode的子类,可以在可以使用JsonNode的任何地方使用ObjectNode。
    暂时还不大懂,以后用到再琢磨琢磨

    2、JSON-> JsonNode

    要使用Jackson将JSON读取到JsonNode中,首先需要创建一个Jackson ObjectMapper实例。 在ObjectMapper实例上,调用readTree()并将JSON源作为参数传递。 这是将JSON反序列化为JsonNode的示例:

    1. @Test
    2. public void testJavaToJsonNode(){
    3. String json = "{ \"f1\" : \"v1\" } ";
    4. ObjectMapper objectMapper=new ObjectMapper();
    5. try {
    6. JsonNode jsonNode = objectMapper.readTree(json);
    7. System.out.println(jsonNode.toString());
    8. } catch (IOException e) {
    9. e.printStackTrace();
    10. }
    11. }

    3. JsonNode->JSON

    要将Jackson的JsonNode写入JSON,还需要一个Jackson ObjectMapper实例。 在ObjectMapper上,调用writeValueAsString()方法或任何适合需要的写入方法。 这是将JsonNode写入JSON的示例:

    1. @Test
    2. public void testJNToNSON(){
    3. String json = "{ \"f1\" : \"v1\" } ";
    4. ObjectMapper objectMapper = new ObjectMapper();
    5. try {
    6. JsonNode jsonNode = objectMapper.readTree(json);
    7. String s=objectMapper.writeValueAsString(jsonNode);
    8. System.out.println(s);
    9. } catch (IOException e) {
    10. e.printStackTrace();
    11. }
    12. }

    4.获取字段

  • 通过get给出字段名获取

    1. {
    2. "field1" : "value1",
    3. "field2" : 999
    4. }
    1. JsonNode jsonNode = ... //parse above JSON into a JsonNode
    2. JsonNode field1 = jsonNode.get("field1");
    3. JsonNode field2 = jsonNode.get("field2");
  • 通过at在路径中获取

    1. {
    2. "identification" : {
    3. "name" : "James",
    4. "ssn: "ABC123552"
    5. }
    6. }
    1. JsonNode nameNode = jsonNode.at("/identification/name");
  • 注意传递给at()方法的参数:字符串/ identification / name。 这是一个JSON路径表达式。 此路径表达式指定从根JsonNode到您要访问其值的字段的完整路径。 这类似于从文件系统根目录到Unix文件系统中文件的路径。

    5.转换JsonNode字段

    Jackson JsonNode类包含一组可以将字段值转换为另一种数据类型的方法。 例如,将String字段值转换为long或相反。 这是将JsonNode字段转换为一些更常见的数据类型的示例:

    1. String f2Str = jsonNode.get("f2").asText();
    2. double f2Dbl = jsonNode.get("f2").asDouble();
    3. int f2Int = jsonNode.get("f2").asInt();
    4. long f2Lng = jsonNode.get("f2").asLong();

    使用默认值转换: 如果JsonNode中的字段可以为null,则在尝试转换它时可以提供默认值。 这是使用默认值调用转换方法的示例:

    1. ObjectMapper objectMapper = new ObjectMapper();
    2. String json = "{ \"f1\":\"Hello\", \"f2\":null }";
    3. JsonNode jsonNode = objectMapper.readTree(json);
    4. String f2Value = jsonNode.get("f2").asText("Default");

    6. ObjectNode

    如前所述,JsonNode类是不可变的。 要创建JsonNode对象图,必须能够更改图中的JsonNode实例,例如 设置属性值和子JsonNode实例等。由于是不可变的,因此无法直接使用JsonNode来实现。

  • 创建ObjectNode
    而是创建一个ObjectNode实例,该实例是JsonNode的子类。 这是一个通过Jackson ObjectMapper createObjectNode()方法创建ObjectNode的示例:

    1. ObjectMapper objectMapper = new ObjectMapper();
    2. ObjectNode objectNode = objectMapper.createObjectNode();
  • Set ObjectNode字段
    要在Jackson ObjectNode上设置字段,可以调用其set()方法,并将字段名称String和JsonNode作为参数传递。 这是在Jackson的ObjectNode上设置字段的示例:

    1. String json = "{ \"f1\" : \"v1\" } ";
    2. ObjectMapper objectMapper=new ObjectMapper();
    3. ObjectNode objectNode = objectMapper.createObjectNode();
    4. try {
    5. JsonNode jsonNode = objectMapper.readTree(json);
    6. JsonNode brand = objectNode.set("childNode", jsonNode);
    7. System.out.println(brand.toString());
    8. } catch (IOException e) {
    9. e.printStackTrace();
    10. }
    1. {"childNode":{"f1":"v1"}}//childNode字段
  • Put ObjectNode字段
    ObjectNode类还具有一组方法,可以直接为字段put(设置)值。 这比尝试将原始值转换为JsonNode并使用set()进行设置要容易得多。 以下是使用put()方法为ObjectNode上的字段设置字符串值的示例:

    1. ObjectMapper objectMapper=new ObjectMapper();
    2. ObjectNode objectNode = objectMapper.createObjectNode();
    3. objectNode.put("field1", "value1");
    4. objectNode.put("field2", 123);
    5. objectNode.put("field3", 999.999);
    6. System.out.println(objectNode.toString());
    1. {"field1":"value1","field2":123,"field3":999.999}
  • 删除ObjectNode字段:使用remove(”fieldname”)

  • 循环ObjectNode字段
    JsonNode类具有一个名为fieldNames()的方法,该方法返回一个Iterator,可以迭代JsonNode的所有字段名称。 我们可以使用字段名称来获取字段值。 这是一个迭代Jackson JsonNode的所有字段名称和值的示例:
    1. Iterator<String> stringIterator = objectNode.fieldNames();
    2. while (stringIterator.hasNext())
    3. {
    4. String next = stringIterator.next();
    5. JsonNode jsonNode = objectNode.get(next);
    6. System.out.println(jsonNode.toString());
    7. }

    Jackson注解

    | 注解 | 用法 | | :—-: | :—- | | _@_JsonProperty | 用于属性,把属性的名称序列化时映射为为另外一个名称。示例:
    @JsonProperty(“birth d ate”)
    private Date birthDate; | | [
    @JsonFormat ](/JsonFormat ) | 用于属性或者方法,把属性的格式序列化时转换成指定的格式。示例:
    [
    @JsonFormat(timezone ](/JsonFormat(timezone ) = “GMT+8”, pattern = “yyyy-MM-dd HH:mm”)
    public Date getBirthDate() | | [
    @JsonPropertyOrder ](/JsonPropertyOrder ) | 用于类, 指定属性在序列化时 json 中的顺序 , 示例:
    @JsonPropertyOrder({ “birth_Date”, “name” })
    public class Person | | [
    @JsonCreator ](/JsonCreator ) | 用于构造方法,和 [@JsonProperty ](/JsonProperty ) 配合使用,适用有参数的构造方法。 示例: [@JsonCreator ](/JsonCreator )
    public Person(@JsonProperty(“name”)String name) {…} | | [
    @JsonAnySetter ](/JsonAnySetter ) | 用于属性或者方法,设置未反序列化的属性名和值作为键值存储到 map 中
    [
    @JsonAnySetter ](/JsonAnySetter )
    public void set(String key, Object value) {
    map.put(key, value);
    } | | [
    @JsonAnyGetter ](/JsonAnyGetter ) | 用于方法 ,获取所有未序列化的属性
    public Map any() { return map; } | | [
    @_JsonRootName ](/JsonRootName ) | 用于定义一个根Key,需要进行配置:
    jackson:
    deserialization.UNWRAP_ROOT_VALUE: true |

一)、Read+Write注解

此类注解可以进行序列化以及反序列化,成为双向注解或者Read+Write注解

1._@_JsonIgnore

Jackson注解@JsonIgnore用于告诉Jackson忽略Java对象的某个属性(字段)。 在将JSON读取到Java对象中以及将Java对象写入JSON时,都将忽略该属性

  1. import com.fasterxml.jackson.annotation.JsonIgnore;
  2. public class PersonIgnore {
  3. @JsonIgnore
  4. public long personId = 0;
  5. public String name = null;
  6. }

上面的类中,personId不会参与序列化以及反序列化

2._@_JsonIgnoreProperties

与@JsonIgnore的作用相同,但是放在类上面,在内部指定不参与序列化和反序列化的成员变量

  1. import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
  2. @JsonIgnoreProperties({"firstName", "lastName"})
  3. public class PersonIgnoreProperties {
  4. public long personId = 0;
  5. public String firstName = null;
  6. public String lastName = null;
  7. }

firstName与LastName均不参与序列化和反序列化

3._@_JsonIgnoreType

_@_JsonIgnoreType Jackson注解用于将整个类型(类)标记为在使用该类型的任何地方都将被忽略。

  1. @Data
  2. @NoArgsConstructor
  3. @JsonRootName("car")
  4. public class Car {
  5. private String brand = null;
  6. private int doors = 0;
  7. @JsonIgnore
  8. private String type;
  9. @JsonProperty(value = "Driver")
  10. private Driver driver;
  11. public Car(String brand,int doors,String type,Driver driver){
  12. this.brand=brand;
  13. this.doors=doors;
  14. this.type=type;
  15. this.driver=driver;
  16. }
  17. }
  1. @Data
  2. @JsonIgnoreType
  3. public class Driver {
  4. private String name;
  5. private String sex;
  6. private int age;
  7. }

加上注解后,Driver整个类都将被忽略

  1. {"brand":"tesla","doors":5}

取消注解:

  1. {"brand":"tesla","doors":5,"Driver":{"name":"John Wick","sex":"male","age":29}}

4._@_JsonAutoDetect

暂时没大看懂在干什么
Jackson注解@JsonAutoDetect用于告诉Jackson在读写对象时包括非public修饰的属性。
这是一个示例类,展示如何使用@JsonAutoDetect注解:

  1. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  2. @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )
  3. public class PersonAutoDetect {
  4. private long personId = 123;
  5. public String name = null;
  6. }

JsonAutoDetect.Visibility类包含与Java中的可见性级别匹配的常量,表示ANY,DEFAULT,NON_PRIVATE,NONE,PROTECTED_AND_PRIVATE和PUBLIC_ONLY。

5._@_JsonRootName

对于只有id和name两个字段的POJO来说,正常的序列化结果如下:

  1. {
  2. "id" : 1,
  3. "name" : "book"
  4. }

jackson在序列化时,可以在上述json外面再包裹一层,官方叫做WRAP_ROOT_VALUE,本文中叫做root对象,如下所示,整个json的只有一个键值对,key是aaabbbccc,value内部才是POJO实例的id和name字段的值:

  1. {
  2. "aaabbbccc" : {
  3. "id" : 2,
  4. "name" : "food"
  5. }
  6. }
  • 配置:

    • 在使用ObjectMapper时,使用以下方法使root生效:

      1. objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
    • 在Springboot项目中,可以通过配置文件的方法使其生效:

      1. jackson:
      2. serialization.UNWRAP_ROOT_VALUE: true

      默认值:如果不使用@JsonRootName注解,则root字段默认为实体类的名称,@JsonRootName可以用于指定root的名称
      在SSM项目当中,序列化的工作交给了ResponseEntity,可以将toString的字符数据转化为json的数据格式,因此序列化的工作不需要自己来完成,自己只需要关注反序列化的工作即可
      下面来讨论反序列化的工作

  • 配置反序列化,若不进行配置,jackson依旧无法识别root这个key,得到的值全为null同样需要进行配置

    • 使用ObjecMapper时:

      1. mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
    • 在Springboot项目当中,在配置文件中进行设置:

      1. jackson:
      2. deserialization.UNWRAP_ROOT_VALUE: true

      若不进行配置,
      在使用了@JsonRootName的注解后,@JsonRootName中的值应当与Json字符串的root的值一致,否则会反序列化失败

      二)、Read注解

      1、_@_JsonSetter

      当进行反序列化时,JSON字段与setter方法无法匹配时,通过该注解来指定setter函数,也可认为@JsonProperty的逆向操作

      1. {
      2. "id" : 1234,
      3. "name" : "John"
      4. }

      此处id与成员变量personId无法匹配,因此指定setter方法来进行数据的封装

      1. public class Person {
      2. private long personId = 0;
      3. private String name = null;
      4. public long getPersonId() { return this.personId; }
      5. @JsonSetter("id")
      6. public void setPersonId(long personId) { this.personId = personId; }
      7. public String getName() { return name; }
      8. public void setName(String name) { this.name = name; }
      9. }

      @JsonSetter注解中指定的值是要与此setter方法匹配的JSON字段的名称。 在这种情况下,名称为id,因为这是我们要映射到setPersonId()setter方法的JSON对象中字段的名称。

      2、_@_JsonAnySetter

      Jackson注解@JsonAnySetter表示Jackson为JSON对象中所有无法识别的字段调用相同的setter方法。 “无法识别”是指尚未映射到Java对象中的属性或设置方法的所有字段。
      实体类

      1. @ToString
      2. public class Bag {
      3. private Map<String,Object> properties=new HashMap<>();
      4. private int size;
      5. public void setSize(int size) {
      6. this.size = size;
      7. }
      8. @JsonAnySetter
      9. public void set(String fieldName,Object value){
      10. this.properties.put(fieldName,value);
      11. }
      12. public Object get(String fieldName){
      13. return this.properties.get(fieldName);
      14. }
      15. }
      1. {
      2. "id" : 1234,
      3. "name" : "John",
      4. "size":5
      5. }

      显然可知,id和name都不存在对应的setter函数,无法自动进行数据的封装,通过@JsonAnySetter指定该setter处理无法识别的id和name,进行数据封装,最后便可以正常装配,而对于size,存在对应的setter函数,因此正常装配即可,与@JsonAnySetter无关

      3、_@_JsonCreator

      Jackson注解@JsonCreator用于告诉Jackson该Java对象具有一个构造函数(“创建者”),该构造函数可以将JSON对象的字段与Java对象的字段进行匹配。

      1. public class PersonImmutable {
      2. private long id = 0;
      3. private String name = null;
      4. @JsonCreator
      5. public PersonImmutable(
      6. @JsonProperty("id") long id,
      7. @JsonProperty("name") String name ) {
      8. this.id = id;
      9. this.name = name;
      10. }
      11. public long getId() {
      12. return id;
      13. }
      14. public String getName() {
      15. return name;
      16. }
      17. }

      要告诉Jackson应该调用PersonImmutable的构造函数,我们必须在构造函数中添加@JsonCreator注解。 我们还必须注解构造函数的参数,以告诉Jackson将JSON对象中的哪些字段传递给哪些构造函数参数。

      三)、Write注解

      Jackson还包含一组注解,这些注解可以影响Jackson将Java对象序列化(写入)到JSON的方式。

      1、_@_JsonInclude

      Jackson注解@JsonInclude告诉Jackson仅在某些情况下包括属性。 例如,仅当属性为非null,非空或具有非默认值时,才应包括该属性。 这是显示如何使用@JsonInclude注解的示例:

      1. import com.fasterxml.jackson.annotation.JsonInclude;
      2. @JsonInclude(JsonInclude.Include.NON_EMPTY)
      3. public class PersonInclude {
      4. public long personId = 0;
      5. public String name = null;
      6. }

      此处表示该类的参数不能为null且不能为空字符串
      同时还有者NON_ABSENT,NON_EMPTY等其他参数

  • ALWAYS:表示总是序列化所有属性

  • NON_NULL:表示序列化非null属性
  • NON_ABSENT:表示序列化非null或者引用类型缺省值,例如java8的Optional类,这个选中通常与Optional一起使用
  • NON_EMPTY:表示序列化非Empty的属性,例如空的集合不会被序列化
  • NON_DEFAULT:仅包含与POJO属性默认值不同的值
  • CUSTOM:由{_@_link JsonInclude#valueFilter}指定值本身,或由{_@_link JsonInclude#contentFilter}指定结构化类型的内容,由过滤器对象的equals方法进行序列化,返回true则会被排除,返回false会被序列化
    USE_DEFAULTS:使用默认值

    2、_@_JsonGetter

    _@_JsonGetter Jackson注解用于告诉Jackson,应该通过调用getter方法而不是通过直接字段访问来获取某个字段值

    3、_@_JsonAnyGetter

    _@_JsonAnyGetter Jackson注解使您可以将Map用作要序列化为JSON的属性的容器。

    1. public class PersonAnyGetter {
    2. private Map<String, Object> properties = new HashMap<>();
    3. @JsonAnyGetter
    4. public Map<String, Object> properties() {
    5. return properties;
    6. }
    7. }
    1. @Test
    2. public void test3(){
    3. Map<String,Object> map=new HashMap<>();
    4. map.put("name","Jhon Wick");
    5. Car car=new Car();
    6. car.setBrand("ford");
    7. car.setDoors(3);
    8. car.setType("oil");
    9. car.setDriver(null);
    10. map.put("car",car);
    11. map.put("age",29);
    12. PersonAnyGetter personAnyGetter=new PersonAnyGetter();
    13. personAnyGetter.setProperties(map);
    14. ObjectMapper objectMapper=new ObjectMapper();
    15. try {
    16. String s = objectMapper.writeValueAsString(personAnyGetter);
    17. System.out.println(s);
    18. } catch (JsonProcessingException e) {
    19. e.printStackTrace();
    20. }
    21. }

    序列化的结果为:

    1. {
    2. "car":{"brand":"ford","type":"oil","doors":3,"Driver":null},
    3. "name":"Jhon Wick",
    4. "age":29
    5. }

    当看到@JsonAnyGetter注解时,Jackson将从@JsonAnyGetter注解的方法中获取返回的Map,并将该Map中的每个键值对都视为一个属性。 换句话说,Map中的所有键值对都将作为PersonAnyGetter对象的一部分序列化为JSON。

    4、_@_JsonPropertyOrder

    _@_JsonPropertyOrder Jackson注解可用于指定将Java对象的字段序列化为JSON的顺序。
    将上一个注解的结果进行排序后的结果为:

    1. @JsonPropertyOrder({"brand","type","doors","driver"})
    1. {"car":{"brand":"ford","type":"oil","doors":3,"Driver":null},"name":"Jhon Wick","age":29}

    排序后type比doors首先序列化输出

    5、_@_JsonRawValue

    _@_JsonRawValue Jackson注解告诉Jackson该属性值应直接写入JSON输出。 如果该属性是字符串,Jackson通常会将值括在引号中,但是如果使用@JsonRawValue属性进行注解,Jackson将不会这样做。

    1. @Data
    2. public class Driver {
    3. private String name;
    4. @JsonRawValue
    5. private String sex;
    6. private int age;
    7. }
    1. {
    2. "name":"Jhon Wick",
    3. "sex":male,
    4. "age":29
    5. }

    对比name与sex的结果,可以发现同为字符串,sex的引号消失

  • 下面这个例子可以说明此注解究竟有何用处

    1. public class PersonRawValue {
    2. public long personId = 0;
    3. @JsonRawValue
    4. public String address =
    5. "{ \"street\" : \"Wall Street\", \"no\":1}";
    6. }

    序列化结果:得到了一个嵌套字段

    1. {
    2. "personId":0,
    3. "address":{ "street" : "Wall Street","no":1}
    4. }

    如果没有该注解,则得到以下结果,显然不是预期的结果

    1. {
    2. "personId":0,
    3. "address":"{ \"street\" : \"Wall Street\", \"no\":1}"
    4. }

    6、_@_JsonValue

    Jackson注解@JsonValue告诉Jackson,Jackson不应该尝试按照常规方法序列化对象本身,而应在对象上调用将对象序列化为JSON字符串的方法。
    在下面的例子当中,按照自己自定义的toJson方法进行序列化

    1. @Data
    2. public class Driver {
    3. private String name;
    4. @JsonRawValue
    5. private String sex;
    6. private int age;
    7. @JsonValue
    8. public String toJson(){
    9. return this.name+","+this.age;
    10. }
    11. }

    得到的结果为:

    1. "Jhon Wick,29"

    :得到的Json字符串中引号也属于其中的一部分,即s.charAt(0)=”


原文1:https://www.cnblogs.com/klhans/p/12583751.html
原文2:https://blog.csdn.net/boling_cavalry/article/details/107135958
原文3:https://juejin.cn/post/6844904166809157639