JSON解析-Jackson

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);
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值