Jackson -- ObjectMapper

目录

1.简介

 2 Jackson的数据绑定

3 反序列化

3.1 从JSON字符串读取Java对象

3.2 从JSON文件读取Java对象

3.3 从URL获取JSON数据读取Java对象

3.4 从Java InputStream获取JSON数据读取Java对象

3.5 从字节数组获取JSON数据读取Java对象

3.6 从JSON数组字符串读取Java对象数组

3.7 从JSON数组字符串读取Java List对象

3.8 从JSON字符串读取Java Map对象

3.9 定制反序列化过程

4.属性配置

4.1 忽略Java对象没有的JSON属性 

4.2 JSON属性值为NULL且对应Java原生类型产生的异常

5.序列化

5.1 把对象序列化成JSON

5.2 自定义序列化过程

6.Jackson的日期格式化

7.Jackson的树模型

8.redis使用jackson序列化


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原生类型产生的异常

可以配置ObjectMapperFeature, 使其在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;
    }

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值