Jackson ObjectMapper

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

Jackson ObjectMapper还可以从 Java 对象创建JSON。从Java对象生成JSON也称为将Java对象序列化为JSON。

Jackson 对象映射器可以将 JSON 解析为您开发的类的对象,或者解析为内置的 JSON 树模型对象。

顺便说一句,它之所以被称为ObjectMapper是因为它将 JSON 映射为 Java 对象(反序列化),或者将 Java 对象映射为JSON(序列化)。

Jackson Databind

ObjectMapper位于 Jackson Databind 项目中,因此应用程序需要在其类路径上引入该项目才能工作。

Jackson ObjectMapper Example

这是一个简单的 Java JacksonObjectMapper示例:

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 的来源(字符串、流或文件)

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

Jackson ObjectMapper 如何将 JSON 字段与 Java 字段匹配

要使用 Jackson 正确读取 JSON 中的 Java 对象,了解 Jackson 如何将 JSON 对象的字段映射到 Java 对象的字段非常重要。

默认情况下,Jackson 通过将 JSON 字段的名称与 Java 对象中的 getter 和 setter 方法相匹配,将 JSON 对象的字段映射到 Java 对象中的字段。Jackson 删除了 getter 和 setter 方法名称中的“get”和“set”部分,并将剩余名称的第一个字符转换为小写。

例如,名为brand的 JSON 字段与名为getBrand()和setBrand()的 Java getter 和 setter 方法相匹配。名为engineNumber的 JSON 字段将与名为getEngineNumber()和setEngineNumber()的 getter 和 setter 方法相匹配。

如果需要以不同的方式将 JSON 对象字段与 Java 对象字段匹配,则需要使用自定义序列化器和反序列化器。

Jackson Annotations

Jackson 包含一组 Java 注释,可以使用它们来修改 Jackson 从 Java 对象读取和写入 JSON 的方式。

从 JSON 字符串读取对象

从 JSON 字符串读取 Java 对象非常简单。JSON 字符串作为第一个参数传递给ObjectMappers readValue()方法

ObjectMapper objectMapper = new ObjectMapper();

String carJson =
    "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

Car car = objectMapper.readValue(carJson, Car.class);

从 JSON Reader 读取对象

ObjectMapper objectMapper = new ObjectMapper();

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 4 }";
Reader reader = new StringReader(carJson);

Car car = objectMapper.readValue(reader, Car.class);

从 JSON 文件读取对象

ObjectMapper objectMapper = new ObjectMapper();

File file = new File("data/car.json");

Car car = objectMapper.readValue(file, Car.class);

通过 URL 从 JSON 读取对象

ObjectMapper objectMapper = new ObjectMapper();

URL url = new URL("file:data/car.json");

Car car = objectMapper.readValue(url, Car.class);

从 JSON 输入流读取对象

ObjectMapper objectMapper = new ObjectMapper();

InputStream input = new FileInputStream("data/car.json");

Car car = objectMapper.readValue(input, Car.class);

从 JSON 字节数组读取对象

ObjectMapper objectMapper = new ObjectMapper();

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

byte[] bytes = carJson.getBytes("UTF-8");

Car car = objectMapper.readValue(bytes, Car.class);

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

String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";

ObjectMapper objectMapper = new ObjectMapper();

Car[] cars2 = objectMapper.readValue(jsonArray, Car[].class);

从 JSON 数组字符串读取对象列表

String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";

ObjectMapper objectMapper = new ObjectMapper();

List<Car> cars1 = objectMapper.readValue(jsonArray, new TypeReference<List<Car>>(){});

从 JSON 字符串读取MAP

Jackson ObjectMapper还可以从 JSON 字符串读取Java Map 。如果事先不知道要解析的确切 JSON 结构,这会很有用。

String jsonObject = "{\"brand\":\"ford\", \"doors\":5}";

ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> jsonMap = objectMapper.readValue(jsonObject,
    new TypeReference<Map<String,Object>>(){});

忽略未知的 JSON 字段

有时,JSON 中的字段数量多于 Java 对象中的字段数量。默认情况下,Jackson 在这种情况下会抛出异常,表示它不知道字段 XYZ,因为在 Java 对象中未找到该字段。

然而,有时应该允许 JSON 中的字段多于相应 Java 对象中的字段。例如,如果正在从 REST 服务解析 JSON,其中包含的数据比需要的多得多。在这种情况下,Jackson 能够通过配置忽略这些额外字段。以下是配置 Jackson ObjectMapper忽略未知字段的方式:

objectMapper.configure(
    DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Null 值失败

如果 JSON 值为 null的字段需要置为失败,则可以通过 Jackson 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; }
}
{ "brand":"Toyota", "doors":null }

Jackson ObjectMapper默认忽略null primitive字段的值

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

将FAIL_ON_NULL_FOR_PRIMITIVES配置值设置为 true 时,尝试将 null JSON 字段解析为 Java primitive字段时会出现异常。

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

自定义反序列化器

有时,可能希望 Jackson ObjectMapper以非默认方式处理 JSON 和 Java 对象。可以添加自定义反序列化器。

以下是如何通过 Jackson 注册和使用自定义反序列化器:

String json = "{ \"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);

Car car = mapper.readValue(json, Car.class);
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;
    }
}

从对象生成 JSON

Jackson ObjectMapper还可以用于从对象生成 JSON。可以使用以下方法之一来执行此操作:

  • writeValue()
  • writeValueAsString()
  • writeValueAsBytes()
ObjectMapper objectMapper = new ObjectMapper();

Car car = new Car();
car.brand = "BMW";
car.doors = 4;

objectMapper.writeValue(
    new FileOutputStream("data/output-2.json"), car);
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}

自定义序列化器

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);
{"producer":"Mercedes","doorCount":5}
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();
    }
}

Jackson日期格式

默认情况下,Jackson 会将java.util.Date对象序列化为其long值,即自 1970 年 1 月 1 日以来的毫秒数。但是,Jackson 还支持将日期格式化为字符串。

Date to long

public class Transaction {
    private String type = null;
    private Date date = null;

    public Transaction() {
    }

    public Transaction(String type, Date date) {
        this.type = type;
        this.date = date;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }
}
Transaction transaction = new Transaction("transfer", new Date());

ObjectMapper objectMapper = new ObjectMapper();
String output = objectMapper.writeValueAsString(transaction);

System.out.println(output);
{"type":"transfer","date":1516442298301}

Date to String

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
objectMapper2.setDateFormat(dateFormat);

String output2 = objectMapper2.writeValueAsString(transaction);
System.out.println(output2);
{"type":"transfer","date":"2018-01-20"}

Jackson JSON 树模型

Jackson 有一个内置的树模型,可用于表示 JSON 对象。Jackson 树模型由JsonNode类来表示。

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

ObjectMapper objectMapper = new ObjectMapper();

try {

    JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);

} catch (IOException e) {
    e.printStackTrace();
}

ObjectMapper还有一个特殊的readTree()方法,返回一个 JsonNode.

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

ObjectMapper objectMapper = new ObjectMapper();

try {

    JsonNode jsonNode = objectMapper.readTree(carJson);

} catch (IOException e) {
    e.printStackTrace();
}

Jackson JsonNode 类

JsonNode类允许以一种非常灵活和动态的方式将 JSON 作为 Java 对象进行导航。无论访问字段、数组还是嵌套对象,您都可以使用类的get()方法获取JsonNode。通过提供字符串作为 get()方法的参数. 如果JsonNode 代表一个数组,则需要将索引传递给get()方法。

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5," +
        "  \"owners\" : [\"John\", \"Jack\", \"Jill\"]," +
        "  \"nestedObject\" : { \"field\" : \"value\" } }";

ObjectMapper objectMapper = new ObjectMapper();


try {

    JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);

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

转换 Object to JsonNode

可以使用 Jackson ObjectMapper 将 Java 对象转换为转换JsonNode对象

ObjectMapper objectMapper = new ObjectMapper();

Car car = new Car();
car.brand = "Cadillac";
car.doors = 4;

JsonNode carJsonNode = objectMapper.valueToTree(car);

转换JsonNode to Object

ObjectMapper objectMapper = new ObjectMapper();

String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

JsonNode carJsonNode = objectMapper.readTree(carJson);

Car car = objectMapper.treeToValue(carJsonNode);

使用 Jackson ObjectMapper 读取和写入其他数据格式

可以使用 Jackson 读取和写入 JSON 以外的其他数据格式。

  • CBOR
  • MessagePack
  • YAML

其中一些数据格式比 JSON 更紧凑,因此存储时占用的空间更少,并且读写速度比 JSON 更快。

使用 Jackson ObjectMapper 读写 CBOR

CBOR 是一种二进制数据格式,与 JSON 兼容,但比 JSON 更紧凑,因此读写速度更快。Jackson ObjectMapper 可以像读写 JSON 一样读写 CBOR。为了使用 Jackson 读写 CBOR,需要项目添加额外的 Maven 依赖项。

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-cbor</artifactId>
    <version>${version}</version>
</dependency>
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;

public class CborJacksonExample {
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper(new CBORFactory());

        Employee employee = new Employee("John Doe", "john@doe.com");

        try {
            byte[] cborBytes = objectMapper.writeValueAsBytes(employee);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;

import java.io.IOException;

public class CborJacksonExample {
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper(new CBORFactory());

        Employee employee = new Employee("John Doe", "john@doe.com");

        byte[] cborBytes = null;
        try {
            cborBytes = objectMapper.writeValueAsBytes(employee);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            // normally, rethrow exception here - or don't catch it at all.
        }

        try {
            Employee employee2 = objectMapper.readValue(cborBytes, Employee.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用 Jackson ObjectMapper 读取和写入 MessagePack

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.msgpack.jackson.dataformat.MessagePackFactory;

import java.io.IOException;

public class MessagePackJacksonExample {
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());

        Employee employee = new Employee("John Doe", "john@doe.com");

        byte[] messagePackBytes = null;
        try {
            messagePackBytes = objectMapper.writeValueAsBytes(employee);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            // normally, rethrow exception here - or don't catch it at all.
        }
    }
}

使用 Jackson ObjectMapper 读取和编写 YAML

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.msgpack.jackson.dataformat.MessagePackFactory;

import java.io.IOException;

public class MessagePackJacksonExample {
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());

        Employee employee = new Employee("John Doe", "john@doe.com");

        byte[] messagePackBytes = null;
        try {
            messagePackBytes = objectMapper.writeValueAsBytes(employee);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            // normally, rethrow exception here - or don't catch it at all.
        }
    }
}
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

import java.io.IOException;

public class YamlJacksonExample {

    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());

        Employee employee = new Employee("John Doe", "john@doe.com");

        String yamlString = null;
        try {
            yamlString = objectMapper.writeValueAsString(employee);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            // normally, rethrow exception here - or don't catch it at all.
        }

        try {
            Employee employee2 = objectMapper.readValue(yamlString, Employee.class);

            System.out.println("Done");
        } catch (IOException e) {
            e.printStackTrace();
        }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值