目录
3.4 从Java InputStream获取JSON数据读取Java对象
4.2 JSON属性值为NULL且对应Java原生类型产生的异常
1.简介
Jackson ObjectMapper
类(com.fasterxml.jackson.databind.ObjectMapper
)解析JSON工具序列化: Java对象生成Json
反序列化: Json解析为Java对象
Jackson ObjectMapper
从字符串、流或文件解析Json,转换为java对象,即反序列化Jackson ObjectMapper
把Json解析为用户自定义对象, 或JSON内置的树模型对象,即序列化
2 Jackson依赖
// ObjectMapper对象定义位于Jackson Databind项目中, 所以应用中要添加相关项目路径或依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
</dependency>
3 反序列化
3.1 从JSON字符串读取Java对象
public static void main(String[] args){
ObjectMapper objectMapper = new ObjectMapper();
String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
try {
//从JSON字符串读取Java对象, ObjectMapper.readValue()方法
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();
}
}
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;
}
}
3.2 从JSON文件读取Java对象
// 可以通过FileReader实例从读取JSON,也可以直接使用File对象
ObjectMapper objectMapper = new ObjectMapper();
File file = new File("data/car.json");
Car car = objectMapper.readValue(file, Car.class);
3.3 从URL获取JSON数据读取Java对象
// 可以通过URL(java.net.URL)获取JSON数据后读取Java对象
ObjectMapper objectMapper = new ObjectMapper();
URL url = new URL("file:data/car.json");
Car car = objectMapper.readValue(url, Car.class);
3.4 从Java InputStream获取JSON数据读取Java对象
ObjectMapper objectMapper = new ObjectMapper();
InputStream input = new FileInputStream("data/car.json");
Car car = objectMapper.readValue(input, Car.class);
3.5 从字节数组获取JSON数据读取Java对象
ObjectMapper objectMapper = new ObjectMapper();
String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
byte[] bytes = carJson.getBytes("UTF-8");
Car car = objectMapper.readValue(bytes, Car.class);
3.6 从JSON数组字符串读取Java对象数组
// ObjectMapper也可以从JSON数组字符串中读取一组Java对象
// 注意Car类数组作为readValue()方法第二个参数的传入方式, 告诉ObjectMapper期望从JSON读取一组Car实例 。
// JSON源不仅是字符串, 也可以是文件, URL, InputStream, Reader等等
String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
ObjectMapper objectMapper = new ObjectMapper();
Car[] cars2 = objectMapper.readValue(jsonArray, Car[].class);
3.7 从JSON数组字符串读取Java List对象
// 注意传递给readValue()的TypeReference类型参数. 这个参数告诉Jackson读取一"列"Car对象
// Jackson通过反射来生成Java对象, 但是模板会擦除类型, 所以这里用TypeReference进行包装
String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
ObjectMapper objectMapper = new ObjectMapper();
List<Car> cars1 = objectMapper.readValue(jsonArray, new TypeReference<List<Car>>(){});
3.8 从JSON字符串读取Java Map对象
// ObjectMapper可以从JSON字符串读取一个Java Map, 当你不知道要提取的JSON的格式的时候非常有用. 一般会把JSON对象读取到一个JavaMap对象中. 每一个JSON对象的属性都会变成JavaMap中的键值对.
String jsonObject = "{\"brand\":\"ford\", \"doors\":5}";
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> jsonMap = objectMapper.readValue(jsonObject, new TypeReference<Map<String,Object>>(){});
3.9 定制反序列化过程
public static void main(String[] args){
String json = "{ \"brand\" : \"Ford\", \"doors\" : 6 }";
//定义一个模型,该模型使用`CarDeserializer`作为反序列化器
SimpleModule module = new SimpleModule("CarDeserializer", new Version(3, 1, 8, null, null, null));
//指定反序列化器作用的Java类(Car类)
module.addDeserializer(Car.class, new CarDeserializer(Car.class));
ObjectMapper mapper = new ObjectMapper();
//为ObjectMapper添加一个序列化/反序列化的模型
mapper.registerModule(module);
//反序列化Car类
Car car = mapper.readValue(json, Car.class);
}
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;
}
}
4.属性配置
4.1 忽略Java对象没有的JSON属性
读取的JSON数据的属性多于Java对象的属性, 默认情况下Jackson这时会抛出异常, 含义是无法在Java对象中找到未知属性XXX 通过配置Jackson的
Feature
可以让你忽略多余属性objectMapper.configure(
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);或 ObjectMapper.enabled()/disabled()
4.2 JSON属性值为NULL且对应Java原生类型产生的异常
可以配置
ObjectMapper
的Feature
, 使其在JSON字符串包含的属性值是null
, 且该属性对应的Java对象的属性是原生类型(primitive type: int, long, float, double等
)时, 反序列化失败抛出异常.
// Java中的原生数据类型的值不能是null. 所以ObjectMapper默认会忽略null值的原生类型的属性, 可以配置ObjectMapper的Feature让它抛出异常
// objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
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);
// 抛出异常信息:
/**
*Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException:
Cannot map `null` into type int
(set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)
at [Source: (String)
"{ "brand":"Toyota", "doors":null }"; line: 1, column: 29] (through reference chain: jackson.Car["doors"])
*/
5.序列化
5.1 把对象序列化成JSON
// ObjectMapper实例将一个对象生成JSON数据. 可以使用下列方法:
// writeValue()
// writeValueAsString()
// writeValueAsBytes()
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car();
car.brand = "BMW";
car.doors = 4;
// 输出到FileOutputStream
objectMapper.writeValue(new FileOutputStream("data/output-2.json"), car);
// writeValueAsString()和writeValueAsBytes()
String json = objectMapper.writeValueAsString(car);
5.2 自定义序列化过程
public static void main(String[] args){
//用Car类初始化序列化器CarSerializer
CarSerializer carSerializer = new CarSerializer(Car.class);
ObjectMapper objectMapper = new ObjectMapper();
//新建一个序列化模型, 序列化器使用CarSerializer类
SimpleModule module = new SimpleModule("CarSerializer", new Version(2, 1, 3, null, null, null));
//注册carSerializer用于序列化Car
module.addSerializer(Car.class, carSerializer);
objectMapper.registerModule(module);
Car car = new Car();
car.setBrand("Mercedes");
car.setDoors(5);
String carJson = objectMapper.writeValueAsString(car);
}
class CarSerializer extends StdSerializer<Car> {
protected CarSerializer(Class<Car> t) {
super(t);
}
//serialize的第二个参数是一个JsonGenerator实例, 你可以使用该实例序列化一个对象, 这里是Car对象
@override
public void serialize(Car car, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("producer", car.getBrand());
jsonGenerator.writeNumberField("doorCount", car.getDoors());
jsonGenerator.writeEndObject();
}
}
6.Jackson的日期格式化
public static void main(String[] args) {
Transaction transaction = new Transaction("transfer", new Date());
ObjectMapper objectMapper = new ObjectMapper();
String output = objectMapper.writeValueAsString(transaction);
// Jackson默认的把Date序列化为long
// {"type":"transfer","date":1516442298301}
System.out.println(output);
ObjectMapper objectMapper2 = new ObjectMapper();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
objectMapper2.setDateFormat(dateFormat);
String output2 = objectMapper2.writeValueAsString(transaction);
// long型的序列化可读性很差, 因而Jackson提供了文本格式的日期序列化. 可以为ObjectMapper指定一个SimpleDateFormat实例来带格式提取Jackson日期
// {"type":"transfer","date":"2018-01-20"}
System.out.println(output2);
}
@Data
class Transaction {
private String type = null;
private Date date = null;
}
7.Jackson的树模型
Jackson内置了一个树模型(
tree model
)可以用来表示一个JSON对象. 这个树模型非常有用, 比如你不知道收到的JSON数据的结构, 或者你不想新建一个Java类来表示这个JSON数据, 或者你想在使用或者转发JSON数据前对它进行操作.
Jackson的树模型由JsonNode
类实现. 你可以用ObjectMapper
实例把JSON解析为JsonNode
模型, 就像反序列化出一个自定义类对象一样
String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5," +
" \"owners\" : [\"John\", \"Jack\", \"Jill\"]," +
" \"nestedObject\" : { \"field\" : \"value\" } }";
ObjectMapper objectMapper = new ObjectMapper();
try {
// 方式一 获取jsonNode
JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);
// 方式二 获取jsonNode
JsonNode jsonNode = objectMapper.readTree(carJson);
JsonNode brandNode = jsonNode.get("brand");
String brand = brandNode.asText();
System.out.println("brand = " + brand);
JsonNode doorsNode = jsonNode.get("doors");
int doors = doorsNode.asInt();
System.out.println("doors = " + doors);
JsonNode array = jsonNode.get("owners");
JsonNode jsonNode = array.get(0);
String john = jsonNode.asText();
System.out.println("john = " + john);
JsonNode child = jsonNode.get("nestedObject");
JsonNode childField = child.get("field");
String field = childField.asText();
System.out.println("field = " + field);
} catch (IOException e) {
e.printStackTrace();
}
8.redis使用jackson序列化
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
// redis 序列化数据key的方式
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
// 方法已过期 objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 将类名称序列化到json串中,去掉会导致得出来的是LinkedHashMap对象,直接转换实体对象会失败
objectMapper.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance ,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.WRAPPER_ARRAY);
// 解决jackson2无法反序列化LocalDateTime的问题,因为LocalDateTime没有constructor
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new JavaTimeModule());
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}