ObjectMapper

简介

Jackson ObjectMapper类(com.fasterxml.jackson.databind.ObjectMapper)是使用 Jackson 解析 JSON 最简单的方法。ObjectMapper 可以从字符串、流或文件来解析 JSON,并创建 java 对象或对象图表示已解析的 JSON。将 JSON 解析为java 对象也称从 JSON 反序列化 java 对象

ObjectMapper也可以从 Java 对象创建 JSON。从 java 对象生成 JSON 的过程也称为序列化 java 对象到 JSON

Jackson对象映射器(ObjectMapper)可以把 JSON 解析为用户自定义类对象,或者解析为JSON内置的树模型的对象。

ObjectMapper对象示例

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

readValue() 方法的第一个参数是 JSON数据源(字符串、流或者文件),第二个参数是解析目标Java类,这里传入的是Car.class。

反序列化

ObjectMapper从 JSON 属性匹配到 Java 属性的过程

默认情况下,Jackson 映射一个 JSON 对象的属性到 Java 对象,是用 JSON 属性的名字在 Java对象中查找匹配的 getter/setter 方法。Jackson移除了 getter/setter 方法名中的 get/set 字符部分,并把方法名剩余字符的第一个字符小写,得到的就是 JSON 属性名。

在上面的代码示例中,JSON 属性的名称是 brand,匹配了 Java 类中名为 getBrand()/setBrand() 的方法。JSON 属性的名称是 doors,匹配了getDoors()/setDoors()方法。

如果想用其他方法来匹配 JSON 对象属性和 Java 对象属性,可以自定义序列化/反序列化过程,或者使用其他的 Jackson注解。

从 JSON Reader对象读取 Java对象

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

从 JSON文件中读取Java对象

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

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

例子中使用的是文件URL,也可以使用HTTP URL

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

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

从字节数组获取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);

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

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

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

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

注意传递给readValue()的TypeReference类型参数,这个参数告诉Jackson读取一列“Car”对象

Jackson 通过反射来生成 Java 对象,但是模板会擦除类型,所以这里用 TypeReference 进行包装。

从JSON字符串读取 Java Map 对象

ObjectMapper 可以从 JSON 字符串读取一个 Map,当我们不知道要提取的JSON的格式的时候非常有用。一般会把 JSON 对象读取到一个 Map 对象中,每一个 JSON 对象的属性都会变成 Map中的键值对。

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

特殊情况

忽略Java对象没有的 JSON 属性

有时候我们要读取的 JSON 数据的属性要多于 Java 对象的属性,默认情况下 Jackson 会抛出异常,含义是无法在 Java 对象找到未知属性 XXX

但是,我们有时候又需要允许 JSON 属性多于要产生的 Java 对象的属性。比如,你想从一个 REST服务中获取 JSON 数据,但是它包含的内容远多于你所需要的。这时,通过配置Jackson的 Feature可以使其忽略掉多余的属性。

objectMapper.configure(
    DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

注意:也可以使用ObjectMapper.enabled()/disabled() 方法进行配置

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

可以配置ObjectMapper 的Feature,使其在 JSON 字符串中包含的属性值是 null,且该属性对应的Java 对象的属性时原生类型(primitive type: int, long, float, double等)时,反序列化失败,抛出异常。

修改 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 的类型是 Java 原生类型 int (而不是object)

现在假设有一个 JSON 字符串要匹配 Car类

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

注意属性 doors 的值是 null

Java中的原生数据类型的值不能是 null,所以ObjectMapper默认会忽略 null 值的原生类型的属性,不过也可以配置ObjectMapper的 Feature 让它抛出异常,如下:

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

通过设置FAIL_ON_NULL_FOR_PRIMITIVES属性是true,会在试图把 null 值的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);

异常信息如下:

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"])

序列化

把对象序列化成JSON

ObjectMapper 也可以用来将一个对象生成 JSON 数据,可以使用下列方法:

writeValue()

writeValueAsString()

writeValueAsBytes()

下面是一个把 Car 对象序列化成 JSON 的例子:

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

这里首先创建了一个 ObjectMapper 实例和一个 Car 实例,然后调用 ObjectMapper 的writeValue() 方法把 Car 实例转换成 JSON 后输出到 FileOutputStream。

writeValueAsString() 和 writeValueAsBytes() 也可以从对象中生成 JSON,并且返回一个 String 或者 Byte 数组的 JSON,如下:

ObjectMapper objectMapper = new ObjectMapper();
 
Car car = new Car();
car.brand = "BMW";
car.doors = 4;
 
String json = objectMapper.writeValueAsString(car);
System.out.println(json);

输出结果是:

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

自定义序列化过程

有时候我们不想用 Jackson 默认的序列化过程把一个 Java 对象变成 JSON,比如,我们可能会在 JSON中使用和 Java 对象不同的属性名称,或者我们想完全忽略某些属性。

Jackson 可以为 ObjectMapper 设置一个自定义序列化器(custom serializer)这个序列化器会注册为序列化某个实际的类,然后再 ObjectMapper 执行序列化时调用,比如序列化 Car 对象。

下面的例子展示了如何为 Car 类注册一个自定义序列化器:

//用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);

输出的结果是:

{"producer":"Mercedes","doorCount":5}

下面是 Carserializer 类的定义:

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 {
 
    protected CarSerializer(Class t) {
        super(t);
    }
	@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();
    }
}

注意:serialize 的第二个参数是一个 JsonGenerator实例,我们可以使用这个实例序列化一个对象,这里是 Car 对象。

你可能感兴趣的:(开发语言,java-ee,json)