Spring MVC 默认采用Jackson解析Json,尽管还有一些其它同样优秀的json解析工具,例如Fast Json、GSON,但是出于最小依赖的考虑,也许Json解析第一选择就应该是Jackson。

一、简介
Jackson 是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架。Jackson 社区相对比较活跃,更新速度也比较快, 从 Github 中的统计来看,Jackson 是最流行的 json 解析器之一 。 Spring MVC 的默认 json 解析器便是 Jackson。 Jackson 优点很多。 Jackson 所依赖的 jar 包较少 ,简单易用。与其他 Java 的 json 的框架 Gson 等相比, Jackson 解析大的 json 文件速度比较快;Jackson 运行时占用内存比较低,性能比较好;Jackson 有灵活的 API,可以很容易进行扩展和定制。

Jackson 的 1.x 版本的包名是 org.codehaus.jackson ,当升级到 2.x 版本时,包名变为 com.fasterxml.jackson。

Jackson 的核心模块由三部分组成。

  • jackson-core,核心包,提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator。 Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
  • jackson-annotations,注解包,提供标准注解功能;
  • jackson-databind ,数据绑定包, 提供基于"对象绑定" 解析的相关 API ( ObjectMapper ) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API。

源码地址:FasterXML/jackson


二、依赖
使用Maven构建项目,需要添加依赖:

<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.14.2</version> </dependency><dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.14.2</version> </dependency><dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.14.2</version> </dependency>

当然了,jackson-databind 依赖 jackson-core 和 jackson-annotations,所以可以只显示地添加jackson-databind依赖,jackson-core 和 jackson-annotations 也随之添加到 Java 项目工程中。

<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.14.2</version> </dependency>

下面是Jackson的用法。

三、 ObjectMapper
Jackson 最常用的 API 就是基于"对象绑定" 的 ObjectMapper:

  • ObjectMapper可以从字符串,流或文件中解析JSON,并创建表示已解析的JSON的Java对象。 将JSON解析为Java对象也称为从JSON反序列化Java对象。
  • ObjectMapper也可以从Java对象创建JSON。 从Java对象生成JSON也称为将Java对象序列化为JSON。
  • Object映射器可以将JSON解析为自定义的类的对象,也可以解析置JSON树模型的对象。

之所以称为ObjectMapper是因为它将JSON映射到Java对象(反序列化),或者将Java对象映射到JSON(序列化)。

一)、从JSON中获取Java对象
1、简单示例
一个简单的例子:

Car类:

public class Car { private String brand = null; private int doors = 0; ​ public String getBrand() { return this.brand; } public void setBrand(String brand){ this.brand = brand;} ​ public int getDoors() { return this.doors; } public void setDoors (int doors) { this.doors = doors; } }

将Json转换为Car类对象:

ObjectMapper objectMapper = new ObjectMapper(); ​ String carJson ="{ \"brand\" : \"Mercedes\", \"doors\" : 5 }"; ​ try { Car car = objectMapper.readValue(carJson, Car.class); ​ System.out.println("car brand = " + car.getBrand()); System.out.println("car doors = " + car.getDoors()); } catch (IOException e) { e.printStackTrace(); }

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

例如,名为brand的JSON字段与名为getBrand()和setBrand()的Java getter和setter方法匹配。 名为engineNumber的JSON字段将与名为getEngineNumber()和setEngineNumber()的getter和setter匹配。

如果需要以其他方式将JSON对象字段与Java对象字段匹配,则需要使用自定义序列化器和反序列化器,或者使用一些Jackson注解。

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

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

4、JSON 字符输入流–>Java对象
还可以从通过Reader实例加载的JSON中读取对象。示例如下:

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

5、JSON文件–>Java对象
从文件读取JSON当然可以通过FileReader(而不是StringReader)来完成,也可以通过File对象来完成。 这是从文件读取JSON的示例:

ObjectMapper objectMapper = new ObjectMapper(); ​ File file = new File("data/car.json"); ​ Car car = objectMapper.readValue(file, Car.class);

6、JSON via URL—>Java对象
可以通过URL(java.net.URL)从JSON读取对象,如下所示:

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

7、JSON字节输入流–>Java对象
也可以使用ObjectMapper通过InputStream从JSON读取对象。 这是一个从InputStream读取JSON的示例:
可以通过URL(java.net.URL)从JSON读取对象,如下所示:

ObjectMapper objectMapper = new ObjectMapper(); ​ InputStream input = new FileInputStream("data/car.json"); ​ Car car = objectMapper.readValue(input, Car.class);

8、JSON二进制数组–>Java对象
Jackson还支持从JSON字节数组读取对象。 这是从JSON字节数组读取对象的示例:

ObjectMapper objectMapper = new ObjectMapper(); ​ String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }"; ​ byte[] bytes = carJson.getBytes("UTF-8"); ​ Car car = objectMapper.readValue(bytes, Car.class);

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

String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]"; ​ ObjectMapper objectMapper = new ObjectMapper(); ​ Car[] cars2 = objectMapper.readValue(jsonArray, Car[].class);

需要将Car数组类作为第二个参数传递给readValue()方法。

读取对象数组还可以与字符串以外的其他JSON源一起使用。 例如,文件,URL,InputStream,Reader等。

10、JSON数组字符串–>List
Jackson ObjectMapper还可以从JSON数组字符串读取对象的Java List。 这是从JSON数组字符串读取对象列表的示例:

String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]"; ​ ObjectMapper objectMapper = new ObjectMapper(); ​ List<Car> cars1 = objectMapper.readValue(jsonArray, new TypeReference<List<Car>>(){});

11、JSON字符串–>Map
Jackson ObjectMapper还可以从JSON字符串读取Java Map。 如果事先不知道将要解析的确切JSON结构,这种方法是很有用的。 通常,会将JSON对象读入Java Map。 JSON对象中的每个字段都将成为Java Map中的键,值对。

这是一个使用Jackson ObjectMapper从JSON字符串读取Java Map的示例:

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

12、忽略未知的JSON字段
有时候,与要从JSON读取的Java对象相比,JSON中的字段更多。 默认情况下,Jackson在这种情况下会抛出异常,报不知道XYZ字段异常,因为在Java对象中找不到该字段。

但是,有时应该允许JSON中的字段多于相应的Java对象中的字段。 例如,要从REST服务解析JSON,而该REST服务包含的数据远远超出所需的。 在这种情况下,可以使用Jackson配置忽略这些额外的字段。 以下是配置Jackson ObjectMapper忽略未知字段的示例:

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

13、不允许基本类型为null
如果JSON字符串包含其值设置为null的字段(对于在相应的Java对象中是基本数据类型(int,long,float,double等)的字段),Jackson ObjectMapper默认会处理基本数据类型为null的情况,我们可以可以将Jackson ObjectMapper默认配置为失效,这样基本数据为null就会转换失败。 例如以下Car类:

public class Car { private String brand = null; private int doors = 0; ​ public String getBrand() { return this.brand; } public void setBrand(String brand){ this.brand = brand;} ​ public int getDoors(){ return this.doors; } public void setDoors (int doors) { this.doors = doors; } }

doors字段是一个int类型,它是Java中的基本数据类型。

现在,假设有一个与Car对象相对应的JSON字符串,如下所示:

{ "brand":"Toyota", "doors":null }

请注意,doors字段值为null。 Java中的基本数据类型不能为null值。 默认情况下,Jackson ObjectMapper会忽略原始字段的空值。 但是,可以将Jackson ObjectMapper配置设置为失败。

ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);

在FAIL_ON_NULL_FOR_PRIMITIVES配置值设置为true的情况下,尝试将空JSON字段解析为基本类型Java字段时会遇到异常。 这是一个Java Jackson ObjectMapper示例,该示例将失败,因为JSON字段包含原始Java字段的空值:

ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true); String carJson = "{ \"brand\":\"Toyota\", \"doors\":null }"; Car car = objectMapper.readValue(carJson, Car.class);

结果:

{"brand":"dengtao", "doors":4}

14、自定义反序列化
有时,可能希望以不同于Jackson ObjectMapper缺省方式的方式将JSON字符串读入Java对象。 可以将自定义反序列化器添加到ObjectMapper,可以按需要执行反序列化。

这是在Jackson的ObjectMapper中注册和使用自定义反序列化器的方式:

String json = "{ \"brand\" : \"Ford\", \"doors\" : 6 }"; SimpleModule module = new SimpleModule("CarDeserializer", new Version(3, 1, 8, null, null, null)); module.addDeserializer(Car.class, new CarDeserializer(Car.class)); ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(module); Car car = mapper.readValue(json, Car.class);

自定义反序列化器CarDeserializer类:

public class CarDeserializer extends StdDeserializer<Car> { public CarDeserializer(Class<?> vc) { super(vc); } @Override public Car deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException { Car car = new Car(); while(!parser.isClosed()){ JsonToken jsonToken = parser.nextToken(); if(JsonToken.FIELD_NAME.equals(jsonToken)){ String fieldName = parser.getCurrentName(); System.out.println(fieldName); jsonToken = parser.nextToken(); if("brand".equals(fieldName)){ car.setBrand(parser.getValueAsString()); } else if ("doors".equals(fieldName)){ car.setDoors(parser.getValueAsInt()); } } } return car; } }



二)、将对象写入JSON
1、Java对象–>JSON
Jackson ObjectMapper也可以用于从对象生成JSON。 可以使用以下方法之一进行操作:

  • writeValue()
  • writeValueAsString()
  • writeValueAsBytes()

这是一个从Car对象生成JSON的示例,和上面的实例相反:

ObjectMapper objectMapper = new ObjectMapper(); Car car = new Car(); car.setBrand("BMW"); car.setDoors(4); objectMapper.writeValue(new FileOutputStream("data/output-2.json"), car);

此示例首先创建一个ObjectMapper,然后创建一个Car实例,最后调用ObjectMapper的writeValue()方法,该方法将Car对象转换为JSON并将其写入给定的FileOutputStream。

ObjectMapper的writeValueAsString()和writeValueAsBytes()都从一个对象生成JSON,并将生成的JSON作为String或字节数组返回。 示例如下:

ObjectMapper objectMapper = new ObjectMapper(); Car car = new Car(); car.setBrand("涛"); car.setDoors(4); String json = objectMapper.writeValueAsString(car); System.out.println(json);

运行结果:

{"brand":"涛", "doors":4}




更多:https://zhuanlan.zhihu.com/p/341391723