1.Jackson简介
简介:Jackson是一个简洁的方式去解析JSON开源包。Jackson可以解析JSON从String,Stream,或者file的方式去创建Java对象。Jackson不仅仅可以解析JSON到Java对象,也可以将Java对象解析为JSON字符串。
原理:Java反射机制实现JSON和Java对象间数据自动转换。
日常开发过程中经常会使用json进行数据的传输,这就涉及到了对象和json的相互转化,常用的解决方案有:Jackson(推荐)、谷歌的Gson、阿里的Fastjson,
2.Jackson下载maven依赖
可以从 mvnrepository
上下载。地址:mvnrepository-请点击此处
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
3、SpringBoot默认的json解析格式-Jackson
显示依赖性,可以通过 Show Dependencies 查看
3.1 springboot 之 jackson的两种配置方式
方式一: SpringBoot对于Jackson的配置(通过application.yml)
#指定日期格式,比如yyyy-MM-dd HH:mm:ss,或者具体的格式化类的全限定名
spring.jackson.date-format
#指定日期格式化时区,比如America/Los_Angeles或者GMT+10.
spring.jackson.time-zone
#是否开启Jackson的反序列化
spring.jackson.deserialization
#是否开启json的generators.
spring.jackson.generator
#指定Joda date/time的格式,比如yyyy-MM-ddHH:mm:ss). 如果没有配置的话,dateformat会作为backup
spring.jackson.joda-date-time-format
#指定json使用的Locale.
spring.jackson.locale
#是否开启Jackson通用的特性.
spring.jackson.mapper
#是否开启jackson的parser特性.
spring.jackson.parser
#指定PropertyNamingStrategy(CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES)或者指定PropertyNamingStrategy子类的全限定类名.
spring.jackson.property-naming-strategy
#是否开启jackson的序列化.
spring.jackson.serialization
#指定序列化时属性的inclusion方式,具体查看JsonInclude.Include枚举.
spring.jackson.serialization-inclusion
spring:
jackson:
#日期格式化
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
#设置空如何序列化
default-property-inclusion: non_null
serialization:
#格式化输出
indent_output: true
#忽略无法转换的对象
fail_on_empty_beans: false
deserialization:
#允许对象忽略json中不存在的属性
fail_on_unknown_properties: false
parser:
#允许出现特殊字符和转义符
allow_unquoted_control_chars: true
#允许出现单引号
allow_single_quotes: true
方式二:自定义序列化器
默认对NULL的处理
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder)
{
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
// Include.Include.ALWAYS 默认
// Include.NON_DEFAULT 属性为默认值不序列化
// Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
// Include.NON_NULL 属性为NULL 不序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 允许出现特殊字符和转义符
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
// 允许出现单引号
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
// 字段保留,将null值转为""
objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>()
{
@Override
public void serialize(Object o, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)
throws IOException
{
jsonGenerator.writeString("");
}
});
return objectMapper;
}
自定义对Map、List、String、Boolean、Integer、Object的处理
1. 自定义null值序列化处理器
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
/**
* 自定义null值序列化处理器
*/
public class CustomizeNullJsonSerializer {
/**
* 处理数组集合类型的null值
*/
public static class NullArrayJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartArray();
jsonGenerator.writeEndArray();
}
}
/**
* 处理字符串类型的null值
*/
public static class NullStringJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString("");
}
}
/**
* 处理数值类型的null值
*/
public static class NullNumberJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeNumber(0);
}
}
/**
* 处理boolean类型的null值
*/
public static class NullBooleanJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeBoolean(false);
}
}
/**
* 处理实体对象类型的null值
*/
public static class NullObjectJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeEndObject();
}
}
}
2、序列化程序修改器
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import java.util.Collection;
import java.util.List;
/**
* <pre>
* 此modifier主要做的事情为:
* 1.当序列化类型为数组集合时,当值为null时,序列化成[]
* 2.String类型值序列化为""
*
* </pre>
*/
public class MyBeanSerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
BeanDescription beanDesc,
List<BeanPropertyWriter> beanProperties) {
// 循环所有的beanPropertyWriter
for (int i = 0; i < beanProperties.size(); i++) {
BeanPropertyWriter writer = beanProperties.get(i);
// 判断字段的类型,如果是数组或集合则注册nullSerializer
if (isArrayType(writer)) {
// 给writer注册一个自己的nullSerializer
writer.assignNullSerializer(new CustomizeNullJsonSerializer.NullArrayJsonSerializer());
}
if (isStringType(writer)) {
writer.assignNullSerializer(new CustomizeNullJsonSerializer.NullStringJsonSerializer());
}
}
return beanProperties;
}
/**
* 是否是数组
*/
private boolean isArrayType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return clazz.isArray() || Collection.class.isAssignableFrom(clazz);
}
/**
* 是否是String
*/
private boolean isStringType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return CharSequence.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz);
}
/**
* 是否是数值类型
*/
private boolean isNumberType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return Number.class.isAssignableFrom(clazz);
}
/**
* 是否是boolean
*/
private boolean isBooleanType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return clazz.equals(Boolean.class);
}
}
3.2 Jackson 常见API
从JSON字符串中读取Java对象非常简单。你们已经看过一个例子了。JSON字符串作为第一个参数传递给objectapper的readValue()方法。下面是另一个简单的例子:
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字符串转换为Java对象
import com.example.model.Car;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.SpringApplication;
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();
}
运行结果:
从JSON Reader转换为Java对象
import com.example.model.Car;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.SpringApplication;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
ObjectMapper objectMapper = new ObjectMapper();
try {
String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 4 }";
Reader reader = new StringReader(carJson);
Car car = objectMapper.readValue(reader, Car.class);
System.out.println("car brand = " + car.getBrand());
System.out.println("car doors = " + car.getDoors());
} catch (IOException e) {
e.printStackTrace();
}
运行结果:
===================下面内容读者可自己本地测试=========================
从File 文件中转换为Java对象
ObjectMapper objectMapper = new ObjectMapper();
File file = new File("data/car.json");
Car car = objectMapper.readValue(file, Car.class);
从URL(网络或本地资源) 资源转换为Java对象
Read Object From JSON via URL
ObjectMapper objectMapper = new ObjectMapper();
URL url = new URL("file:data/car.json");
Car car = objectMapper.readValue(url, Car.class);
Read Object From JSON InputStream
ObjectMapper objectMapper = new ObjectMapper();
InputStream input = new FileInputStream("data/car.json");
Car car = objectMapper.readValue(input, Car.class);
Read Object From JSON Byte Array
import com.example.model.Car;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.SpringApplication;
import java.io.IOException;
ObjectMapper objectMapper = new ObjectMapper();
try {
String carJson = "{ \"brand\" : \"Mercedes66\", \"doors\" : 90 }";
byte[] bytes = carJson.getBytes("UTF-8");
Car car = objectMapper.readValue(bytes, Car.class);
System.out.println("car brand = " + car.getBrand());
System.out.println("car doors = " + car.getDoors());
} catch (IOException e) {
e.printStackTrace();
}
运行结果:
Read Object Array From JSON Array String
从JSON字符数组中转换为Java对象数组(Array)
try {
String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
ObjectMapper objectMapper = new ObjectMapper();
Car[] cars2 = objectMapper.readValue(jsonArray, Car[].class);
for (Car car: cars2) {
System.out.println("car brand = " + car.getBrand());
System.out.println("car doors = " + car.getDoors());
}
} catch (JsonProcessingException e) {
e.printStackTrace();
}
运行结果:
Read Object List From JSON Array String
从JSON字符数组中转换为Java对象列表(List)
import com.example.model.Car;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.SpringApplication;
import java.util.List;
try {
String jsonArray = "[{\"brand\":\"ford1122\"}, {\"brand\":\"Fiat3344\"}]";
ObjectMapper objectMapper = new ObjectMapper();
List<Car> cars1 = objectMapper.readValue(jsonArray, new TypeReference<List<Car>>(){});
for (Car car: cars1 ) {
System.out.println("car brand = " + car.getBrand());
System.out.println("car doors = " + car.getDoors());
}
} catch (JsonProcessingException e) {
e.printStackTrace();
}
运行结果:
Read Map from JSON String
从JSON字符串中转换为Java的Map存储
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.SpringApplication;
import java.util.Iterator;
import java.util.Map;
try {
String jsonObject = "{\"brand\":\"ford\", \"doors\":5}";
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> jsonMap = objectMapper.readValue(jsonObject,
new TypeReference<Map<String,Object>>(){});
Iterator it = jsonMap.keySet().iterator();
String key;
Object value;
while(it.hasNext()){
key = it.next().toString();
value = jsonMap.get(key);
System.out.println(key+"--"+value);
}
} catch (JsonProcessingException e) {
e.printStackTrace();
}
运行结果:
有时候,JSON中的字段比希望从JSON中读取的Java对象中的字段要多。默认情况下,Jackson在这种情况下抛出一个异常,说它不知道字段XYZ,因为在Java对象中找不到它。 然而,有时应该允许JSON中比相应的Java对象中包含更多的字段。例如,如果您正在解析来自REST服务的JSON,其中包含的数据比您需要的多得多。在这种情况下,Jackson允许您通过Jackson配置忽略这些额外的字段。下面是如何配置Jackson objectapper以忽略未知字段:
当FAIL_ON_NULL_FOR_PRIMITIVES配置值设置为true时,当试图将一个空JSON字段解析为一个原始Java字段时,您将会得到一个异常。下面是一个Java Jackson objectapper示例,它将失败,因为一个JSON字段包含一个原始Java字段的空值:
import com.example.model.Car;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.SpringApplication;
try {
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);
System.out.println("car brand = " + car.getBrand());
System.out.println("car doors = " + car.getDoors());
} catch (Exception e) {
e.printStackTrace();
}
运行结果:
3.3 自定义反序列化器
有时,您可能希望以不同于Jackson objectapper默认情况下的方式将JSON字符串读入Java对象。您可以向objectapper添加一个自定义反序列化器,它可以按照您希望的方式执行反序列化。
下面是如何注册和使用Jackson objectapper的自定义反序列化器:
import com.example.model.Car;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.boot.SpringApplication;
try {
String carJson = "{ \"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);
ObjectMapper objectMapper = new ObjectMapper();
Car car = objectMapper.readValue(carJson, Car.class);
System.out.println("car brand = " + car.getBrand());
System.out.println("car doors = " + car.getDoors());
} catch (Exception e) {
e.printStackTrace();
}
CarDeserializer类是这样的:
package com.example.demo;
import com.example.model.Car;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
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;
}
}
运行结果:
3.4 从对象写入JSON
可以将Java对象输出到,JSON字符串,Byte数组,File外部文件中,OutPutStream输出流中
Jackson objectapper 还可以用于从对象生成JSON。您可以使用以下方法之一:
writeValue ()
writeValueAsString ()
writeValueAsBytes ()
下面是一个从Car对象生成JSON的例子,就像前面的例子一样:
这个示例首先创建一个objectapper,然后是一个Car实例,最后调用objectapper的writeValue()
方法,该方法将Car对象转换为JSON,并将其写入给定的FileOutputStream。
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car();
car.brand = "BMW";
car.doors = 4;
objectMapper.writeValue(new FileOutputStream("data/output-2.json"), car);
objectapper的writeValueAsString()和writeValueAsBytes()
都从对象生成JSON,并以字符串或字节数组的形式返回生成的JSON。下面是一个示例,演示如何调用writeValueAsString():
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car();
car.brand = "BMW";
car.doors = 4;
String json = objectMapper.writeValueAsString(car);
System.out.println(json);
这个例子的JSON输出是:
{"brand":"BMW","doors":4}
有时候,希望将Java对象序列化为JSON,这与Jackson默认的做法不同。例如,您可能希望在JSON中使用与Java对象不同的字段名,或者您可能希望完全省略某些字段。
Jackson使您能够在objectapper
上设置自定义序列化器。这个序列化器为某个类注册,然后在objectapper被要求序列化Car对象时调用。下面是一个示例,展示了如何为Car类注册一个自定义序列化器:
自定义的序列化器
package com.example.demo;
import com.example.model.Car;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
public class CarSerializer extends StdSerializer<Car> {
protected CarSerializer(Class<Car> t) {
super(t);
}
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();
}
}
try {
CarSerializer carSerializer = new CarSerializer(Car.class);
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module =
new SimpleModule("CarSerializer",
new Version(2, 1, 3, null, null, null));
module.addSerializer(Car.class, carSerializer);
objectMapper.registerModule(module);
Car car = new Car();
car.setBrand("Mercedes");
car.setDoors(5);
String carJson = objectMapper.writeValueAsString(car);
System.out.println(carJson);
} catch (Exception e) {
e.printStackTrace();
}
执行结果:
4、工具类
参考,可以直接使用
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
public class JacksonUtils {
private JacksonUtils() {
}
public static String toJsonString(Object object) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule())
.registerModule(new ParameterNamesModule()).registerModule(new Jdk8Module())
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
return mapper.writeValueAsString(object);
}
public static <T> T toJavaObject(String jsonString, Class<T> valueType) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule())
.registerModule(new ParameterNamesModule()).registerModule(new Jdk8Module())
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
return mapper.readValue(jsonString, valueType);
}
public static <T> T toJavaObject(String jsonString, TypeReference<T> typeReference) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule())
.registerModule(new ParameterNamesModule()).registerModule(new Jdk8Module())
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
return mapper.readValue(jsonString, typeReference);
}
}