Jackson

Jackson 是 Java JSON API,它提供了几种使用 JSON 的方式。Jackson 是目前最流行的 Java JSON API 之一。您可以在这里找到 Jackson:https://github.com/FasterXML/jackson
  • Jackson 包含 2 个不同的 JSON 解析器:
    • Jackson ObjectMapper,它将 JSON 解析为自定义 Java 对象或 Jackson 特定的树结构(树模型)。
    • Jackson JsonParser 是 Jackson 的 JSON 提取解析器,一次解析 JSON 一个令牌。
  • Jackson 还包含两个 JSON 生成器:
    • Jackson ObjectMapper 可以从自定义 Java 对象或 Jackson 特定的树结构(树模型)生成 JSON。
    • Jackson JsonGenerator 一次可以生成一个 JSON 令牌。

Jackson 可以轻松的将 Java 对象转换成 JSON 对象和 XML 文档,同样也可以将 JSON、XML 转换成 Java 对象。在项目中如果要引入 Jackson,可以直接利用 Maven 或者 Gradle 引入:

<properties>
  ...
  <!-- Use the latest version whenever possible. -->
  <jackson.version>2.7.0</jackson.version>
  ...
</properties>
<dependencies>
  ...
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${jackson.version}</version>
  </dependency>
  ...
</dependencies>Copy to clipboardErrorCopied

注意,databind 项目已经自动依赖了 jackson-core 与 jackson-annotation,不需要额外重复引入。

JSON Tree Model

Jackson 具有内置的树模型,可用于表示 JSON 对象。如果您不知道接收到的 JSON 的外观,或者由于某种原因而不能(或者只是不想)创建一个类来表示它,那么 Jackson 的树模型将非常有用。如果您需要在使用或转发 JSON 之前对其进行操作,则 Jackson 树模型也很有用。所有这些情况都可以在数据流场景中轻易发生。Jackson 树模型由 JsonNode 类表示。您可以使用 Jackson ObjectMapper 将 JSON 解析为 JsonNode 树模型,就像使用您自己的类一样。

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
ObjectMapper objectMapper = new ObjectMapper();
try {
    JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);
} catch (IOException e) {
    e.printStackTrace();
}Copy to clipboardErrorCopied

如您所见,只需将 JsonNode.class 作为第二个参数传递给 readValue() 方法,而不是本教程前面的示例中使用的 Car.class,就可以将 JSON 字符串解析为 JsonNode 对象而不是 Car 对象。。

ObjectMapper 类还具有一个特殊的 readTree() 方法,该方法始终返回 JsonNode。这是使用 ObjectMapper readTree() 方法将 JSON 解析为 JsonNode 的示例:

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
ObjectMapper objectMapper = new ObjectMapper();
try {
    JsonNode jsonNode = objectMapper.readTree(carJson);
} catch (IOException e) {
    e.printStackTrace();
}Copy to clipboardErrorCopied

通过 JsonNode 类,您可以以非常灵活和动态的方式将 JSON 作为 Java 对象进行导航。如前所述,JsonNode 类在其自己的教程中进行了更详细的介绍,但是我仅在此处向您展示如何使用它的基础知识。

将 JSON 解析为 JsonNode(或 JsonNode 实例树)后,就可以浏览 JsonNode 树模型。这是一个 JsonNode 示例,显示了如何访问 JSON 字段,数组和嵌套对象:

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

请注意,JSON 字符串现在包含一个称为所有者的数组字段和一个称为 nestedObject 的嵌套对象字段。无论您访问的是字段,数组还是嵌套对象,都可以使用 JsonNode 类的 get() 方法。通过将字符串作为参数提供给 get() 方法,您可以访问 JsonNode 的字段。如果 JsonNode 表示数组,则需要将索引传递给 get() 方法。索引指定要获取的数组元素。

可以使用 Jackson ObjectMapper 将 Java 对象转换为 JsonNode,而 JsonNode 是转换后的 Java 对象的 JSON 表示形式。您可以通过 Jackson ObjectMapper valueToTree() 方法将 Java 对象转换为 JsonNode。这是一个使用 ObjectMapper valueToTree() 方法将 Java 对象转换为 JsonNode 的示例:

ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car();
car.brand = "Cadillac";
car.doors = 4;
JsonNode carJsonNode = objectMapper.valueToTree(car);
ObjectMapper objectMapper = new ObjectMapper();
String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
JsonNode carJsonNode = objectMapper.readTree(carJson);
Car car = objectMapper.treeToValue(carJsonNode);

ObjectMapper

Jackson ObjectMapper 类(com.fasterxml.jackson.databind.ObjectMapper)是使用 Jackson 解析 JSON 的最简单方法。Jackson ObjectMapper 可以从字符串,流或文件中解析 JSON,并创建表示已解析的 JSON 的 Java 对象或对象图。将 JSON 解析为 Java 对象也称为从 JSON 反序列化 Java 对象。Jackson ObjectMapper 也可以从 Java 对象创建 JSON。从 Java 对象生成 JSON 也称为将 Java 对象序列化为 JSON。Jackson Object 映射器可以将 JSON 解析为您开发的类的对象,也可以解析为本教程稍后说明的内置 JSON 树模型的对象。顺便说一下,之所以称为 ObjectMapper 是因为它将 JSON 映射到 Java 对象(反序列化),或者将 Java 对象映射到 JSON(序列化)。

public class Car {
    private String brand = null;
    private int doors = 0;
}
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();
}Copy to clipboardErrorCopied

Car.class 是我们自定义的类,其作为第二个参数传入到 readValue 函数中。为了使用 Jackson 正确地从 JSON 读取 Java 对象,重要的是要知道 Jackson 如何将 JSON 对象的字段映射到 Java 对象的字段,因此我将解释 Jackson 是如何做到的。默认情况下,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 注释中的一些。

APIs

读取为对象

ObjectMapper objectMapper = new ObjectMapper();
String carJson =
    "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
// 来自于 JSON 字符串
Car car = objectMapper.readValue(carJson, Car.class);
// 来自于 JSON 数组
String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
Car[] cars2 = objectMapper.readValue(jsonArray, Car[].class);
List<Car> cars1 = objectMapper.readValue(jsonArray, new TypeReference<List<Car>>(){});
// 从 JSON Byte Array 读取
byte[] bytes = carJson.getBytes("UTF-8");
Car car = objectMapper.readValue(bytes, Car.class);
// 读取为 Map
String jsonObject = "{\"brand\":\"ford\", \"doors\":5}";
Map<String, Object> jsonMap = objectMapper.readValue(jsonObject,
    new TypeReference<Map<String,Object>>(){});
// 来自于 StringReader
Reader reader = new StringReader(carJson);
Car car = objectMapper.readValue(reader, Car.class);
// 来自于 JSON 文件
File file = new File("data/car.json");
Car car = objectMapper.readValue(file, Car.class);
// 从 URL 读取
InputStream input = new FileInputStream("data/car.json");
Car car = objectMapper.readValue(input, Car.class);Copy to clipboardErrorCopied

我们可以设置在读取到 Null 的原始类型时抛出异常:

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"])Copy to clipboardErrorCopied

最后,我们也可以注册自定义的解释器:

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;
    }
}
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);Copy to clipboardErrorCopied

序列化为字符串

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);Copy to clipboardErrorCopied

Annotations

Jackson 包含一组 Java 批注,您可以使用这些批注来修改 Jackson 到 Java 对象之间读写 JSON 的方式。Jackson 批注 @JsonIgnore 用于告诉 Jackson 忽略 Java 对象的某个属性(字段)。在将 JSON 读取到 Java 对象中以及将 Java 对象写入 JSON 时,都将忽略该属性。这是使用 @JsonIgnore 批注的示例类:

import com.fasterxml.jackson.annotation.JsonIgnore;
public class PersonIgnore {
    @JsonIgnore
    public long    personId = 0;
    public String  name = null;
}

基础使用

Convert Java to JSON

首先声明有一个简单的 POJO:

// Note: can use getters/setters as well; here we just use public fields directly:
public class MyValue {
  public String name;
  public int age;
// NOTE: if using getters/setters, can keep fields `protected` or `private`
}Copy to clipboardErrorCopied

然后创建一个 ObjectMapper 实例用于进行转化:

mapper.writeValue(new File("result.json"), myResultObject);
// or:
byte[] jsonBytes = mapper.writeValueAsBytes(myResultObject);
// or:
String jsonString = mapper.writeValueAsString(myResultObject);Copy to clipboardErrorCopied

案例:Staff

我们可以参考一个实例,将某个 Staff 的信息转化为 JSON 然后写入到文件中,首先来定义实体类:

public class Staff {
    private String name;
    private int age;
    private String position;
    private BigDecimal salary;
    private List<String> skills;
    //getters and settersCopy to clipboardErrorCopied

然后具体的将 Java 实体类转化为 JSON 的语句为:

// 构建测试对象
private Staff createDummyObject() {
    Staff staff = new Staff();
    staff.setName("test");
    staff.setAge(33);
    staff.setPosition("Developer");
    staff.setSalary(new BigDecimal("7500"));
    List<String> skills = new ArrayList<>();
    skills.add("java");
    skills.add("python");
    staff.setSkills(skills);
    return staff;
}
ObjectMapper mapper = new ObjectMapper();
Staff staff = createDummyObject();
try {
    // Convert object to JSON string and save into a file directly
    mapper.writeValue(new File("staff.json"), staff);
    // Convert object to JSON string
    String jsonInString = mapper.writeValueAsString(staff);
    System.out.println(jsonInString);
    // Convert object to JSON string and pretty print
    jsonInString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(staff);
    System.out.println(jsonInString);
} catch (JsonGenerationException e) {
    e.printStackTrace();
} catch (JsonMappingException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}Copy to clipboardErrorCopied

最终的输出为:

{
  "name": "test",
  "age": 33,
  "position": "Developer",
  "salary": 7500,
  "skills": ["java", "python"]
}Copy to clipboardErrorCopied

将 JSON 转化为 Java

将 JSON 转化为 Java 的实体类同样需要用到 ObjectMapper 对象:

ObjectMapper mapper = new ObjectMapper(); // create once, reuse
MyValue value = mapper.readValue(new File("data.json"), MyValue.class);
// or:
value = mapper.readValue(new URL("http://some.com/api/entry.json"), MyValue.class);
// or:
value = mapper.readValue("{\"name\":\"Bob\", \"age\":13}", MyValue.class);Copy to clipboardErrorCopied

而如果我们要将 JSON 转化为 Java 中的 List 或者 Map 的话,可以采用如下方式:

// 将某个 JSON 转化为数组类型
MyClass[] myObjects = mapper.readValue(json, MyClass[].class);
// 将某个 JSON 转化为 List
String json = "[{\"name\":\"test\"}, {\"name\":\"laplap\"}]";
List<Staff> list = mapper.readValue(json, new TypeReference<List<Staff>>(){});
// 将某个 JSON 转化为 Map
String json = "{\"name\":\"test\", \"age\":33}";
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String,Object>>(){});Copy to clipboardErrorCopied

案例:Staff

ObjectMapper mapper = new ObjectMapper();
try {
    // Convert JSON string from file to Object
    Staff staff = mapper.readValue(new File("D:\\staff.json"), Staff.class);
    System.out.println(staff);
    // Convert JSON string to Object
    String jsonInString = "{\"name\":\"test\",\"salary\":7500,\"skills\":[\"java\",\"python\"]}";
    Staff staff1 = mapper.readValue(jsonInString, Staff.class);
    System.out.println(staff1);
    // Pretty print
    String prettyStaff1 = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(staff1);
    System.out.println(prettyStaff1);
} catch (JsonGenerationException e) {
    e.printStackTrace();
} catch (JsonMappingException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}Copy to clipboardErrorCopied

最终的输出为:

Staff [name=test, age=33, position=Developer, salary=7500, skills=[java, python]]
Staff [name=test, age=0, position=null, salary=7500, skills=[java, python]]
{
  "name" : "test",
  "age" : 0,
  "position" : null,
  "salary" : 7500,
  "skills" : [ "java", "python" ]
}

Jackson 中泛型处理

序列化和反序列化的过程中,泛型是永远离不开的主题,泛型的类型参考如下:

index Name Example
1 ParameterizedType 参数化类型,即泛型;例如:List、Map<K,V>等带有参数化的对象,自定义的如 Box 也是
2 TypeVariable 类型变量,即泛型中的变量;例如:T、K、V 等变量,可以表示任何类;在这需要强调的是,TypeVariable 代表着泛型中的变量,而 ParameterizedType 则代表整个泛型
3 GenericArrayType 泛型数组类型,用来描述 ParameterizedType、TypeVariable 类型的数组;即 List[] 、T[]等
4 Class Class 是 Type 的一个实现类,属于原始类型,是 Java 反射的基础,对 Java 类的抽象
5 WildcardType 泛型表达式(或者通配符表达式),即? extend Number、? super Integer 这样的表达式;WildcardType 虽然是 Type 的子接口,但却不是 Java 类型中的一种

类型

Jackson 的类型转化接口使用方法(几个常用的方法):

public <T> T readValue(JsonParser p, Class<T> valueType)
        throws IOException, JsonParseException, JsonMappingException
{
    return (T) _readValue(getDeserializationConfig(), p, _typeFactory.constructType(valueType));
}
@Override
@SuppressWarnings("unchecked")
public <T> T readValue(JsonParser p, TypeReference<?> valueTypeRef)
    throws IOException, JsonParseException, JsonMappingException
{
    return (T) _readValue(getDeserializationConfig(), p, _typeFactory.constructType(valueTypeRef));
}
@Override
@SuppressWarnings("unchecked")
public final <T> T readValue(JsonParser p, ResolvedType valueType)
    throws IOException, JsonParseException, JsonMappingException
{
    return (T) _readValue(getDeserializationConfig(), p, (JavaType) valueType);
}
public <T> T readValue(JsonParser p, JavaType valueType)
    throws IOException, JsonParseException, JsonMappingException
{
    return (T) _readValue(getDeserializationConfig(), p, valueType);
}Copy to clipboardErrorCopied

最长接受的参数是:Class、JavaType、TypeReference。

JavaType

Jackson 中可能是最终的类型吧,TypeReference 最终还是会转化为 JavaType,那么什么是 JavaType 呢?

Base class for type token classes used both to contain information and as keys for deserializers.
Instances can (only) be constructed by
com.fasterxml.jackson.databind.type.TypeFactory.
Since 2.2 this implements {@link java.lang.reflect.Type} to allow
it to be pushed through interfaces that only expose that type.Copy to clipboardErrorCopied

用于包含信息和作为反序列化器的键的类型标记类的基类。只能通过 TypeFactory 来实例化。通常的使用或者构造方式是:

// 1. 通过objectMapper.construct
JavaType javaType = JacksonConstant.OM.constructType(type);
// 2. 通过TypeProvier
JavaType javaType1 = TypeFactory.defaultInstance().constructType(type);Copy to clipboardErrorCopied

其实方式 1 本质上是 2,源代码如下:

public JavaType constructType(Type t) {
    //本质还是通过TypeFactory来实现的
    return _typeFactory.constructType(t);
}Copy to clipboardErrorCopied

那么 TypeFactory 是如何实例化入参的呢?因为在反序列化的过程中,我们的入参是 Type,但正如我们上面所述的,Type 类包含了五个子类, Class, ParameterizedType, TypeVariable,WildCard,GenericArrayType,查看源码:

protected JavaType _fromAny(ClassStack context, Type type, TypeBindings bindings)
    {
        JavaType resultType;
        // simple class?
        if (type instanceof Class<?>) {
            // Important: remove possible bindings since this is type-erased thingy
            resultType = _fromClass(context, (Class<?>) type, EMPTY_BINDINGS);
        }
        // But if not, need to start resolving.
        else if (type instanceof ParameterizedType) {
            resultType = _fromParamType(context, (ParameterizedType) type, bindings);
        }
        else if (type instanceof JavaType) { // [databind#116]
            // no need to modify further if we already had JavaType
            return (JavaType) type;
        }
        else if (type instanceof GenericArrayType) {
            resultType = _fromArrayType(context, (GenericArrayType) type, bindings);
        }
        else if (type instanceof TypeVariable<?>) {
            resultType = _fromVariable(context, (TypeVariable<?>) type, bindings);
        }
        else if (type instanceof WildcardType) {
            resultType = _fromWildcard(context, (WildcardType) type, bindings);
        } else {
            // sanity check
            throw new IllegalArgumentException("Unrecognized Type: "+((type == null) ? "[null]" : type.toString()));
        }
        // 21-Feb-2016, nateB/tatu: as per [databind#1129] (applied for 2.7.2),
        //   we do need to let all kinds of types to be refined, esp. for Scala module.
        if (_modifiers != null) {
            TypeBindings b = resultType.getBindings();
            if (b == null) {
                b = EMPTY_BINDINGS;
            }
            for (TypeModifier mod : _modifiers) {
                JavaType t = mod.modifyType(resultType, type, b, this);
                if (t == null) {
                    throw new IllegalStateException(String.format(
                            "TypeModifier %s (of type %s) return null for type %s",
                            mod, mod.getClass().getName(), resultType));
                }
                resultType = t;
            }
        }
        return resultType;
    }Copy to clipboardErrorCopied

Jackson 本身会根据类型来生成 JavaType,记录相关的信息。总结来说:JavaType,Jackson 自定义的一个记录入参 Type 的相关类的信息和其他和序列化相关的信息的类。

TypeReference

public abstract class TypeReference<T> implements Comparable<TypeReference<T>>
{
    protected final Type _type;
    protected TypeReference()
    {
        Type superClass = getClass().getGenericSuperclass();
        if (superClass instanceof Class<?>) { // sanity check, should never happen
            throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
        }
        _type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
    }
    public Type getType() { return _type; }
}Copy to clipboardErrorCopied

通用的使用方式是:

Map<String, Staff> json2Map = JacksonConstant.OM.readValue(staffMapJson, new TypeReference<Map<String, Staff>>() {
    });Copy to clipboardErrorCopied

构建一个内部匿名类,名字是运行类下的$number,继承了 TypeReference>,保存了最原始的数据类型,通过:

getClass().getGenericSuperclass()Copy to clipboardErrorCopied

获取 parameterizedType,类型为 TypeReference,通过 parameterizedType.getActualTypeArguments()[0],获取最终的类型: Map,这样的话就保留了需要的类型。

使用

入参为 class

Staff staff1 = mapper.readValue(jsonInString, Staff.class);
//Pretty print
String prettyStaff1 = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(staff1);Copy to clipboardErrorCopied

入参为 type

如果入参的是 type,但是实际上是 class 的话,那么需要构建 JavaType:

Object obj = JacksonConstant.OM.readValue(json, JacksonConstant.OM.constructType(type));
if (obj instanceof Staff) {
    return (Staff) obj;
}Copy to clipboardErrorCopied

如果入参为 ParameterizedType 的话,如果 Map,那么需要转化为 TypeReference,代码 case 如下:

Map<String, Staff> json2Map = JacksonConstant.OM.readValue(staffMapJson, new TypeReference<Map<String, Staff>>() {
});Copy to clipboardErrorCopied

同理可得,对于 List 的反序列化可以推断为如下:

public static List<Staff> json2List() throws IOException {
    String json = "[{\"name\":\"rb.x\",\"age\":1,\"position\":\"sh\",\"salary\":100.23,\"skills\":[\"java\",\"mysql\"]}]";
    //在反序列化为List的过程中,list<T> 和Map<K,V>本质上是parameterizedType
    List<Staff> staffList = JacksonConstant.OM.readValue(json, new TypeReference<List<Staff>>() {
    });
    System.out.println(staffList.size());
    return staffList;
}

类注解

Properties(属性处理)

Rename(属性重命名)

public class Name {
  @JsonProperty("firstName")
  public String _first_name;
}Copy to clipboardErrorCopied

在将 Name 实体类转化为 JSON 的时候,就会变成:

{ "firstName": "Bob" }Copy to clipboardErrorCopied

Ignore(属性忽略)

public class Value {
  public int value;
  @JsonIgnore
  public int internalValue;
}Copy to clipboardErrorCopied

最终生成的 JSON 是如下格式:

{ "value": 42 }Copy to clipboardErrorCopied

也可以在类的头部统一声明:

@JsonIgnoreProperties({ "extra", "uselessValue" })
public class Value {
  public int value;
}Copy to clipboardErrorCopied

那么如下的 JSON 字符串也是可以被转化为该实体类的:

{ "value": 42, "extra": "fluffy", "uselessValue": -13 }Copy to clipboardErrorCopied

对于意外地未知属性,也可以统一忽略:

@JsonIgnoreProperties(ignoreUnknown = true)
public class PojoWithAny {
  public int value;
}Copy to clipboardErrorCopied

@JsonView(动态控制展示的成员变量)

首先定义一个简单的 View 控制类:

public class Views {
  public static class Normal {}
  public static class Manager extends Normal {}
}Copy to clipboardErrorCopied

在下面的代码实现中,如果是选择了 Normal View,那么 salary 属性将会被隐藏,而在 Manager View 状态下,任何属性都会被展示。

public class Staff {
    @JsonView(Views.Normal.class)
    private String name;
    @JsonView(Views.Normal.class)
    private int age;
    @JsonView(Views.Normal.class)
    private String position;
    @JsonView(Views.Manager.class)
    private BigDecimal salary;
    @JsonView(Views.Normal.class)
    private List<String> skills;Copy to clipboardErrorCopied

在进行 Object 转化为 JSON 的过程中,进行视图控制:

public class Jackson2Example {
  public static void main(String[] args) {
    Jackson2Example obj = new Jackson2Example();
    obj.run();
  }
  private void run() {
    ObjectMapper mapper = new ObjectMapper();
    Staff staff = createDummyObject();
    try {
      // Salary will be hidden
      System.out.println("Normal View");
      String normalView = mapper
        .writerWithView(Views.Normal.class)
        .writeValueAsString(staff);
      System.out.println(normalView);
      String jsonInString =
        "{\"name\":\"mkyong\",\"age\":33,\"position\":\"Developer\",\"salary\":7500,\"skills\":[\"java\",\"python\"]}";
      Staff normalStaff = mapper
        .readerWithView(Views.Normal.class)
        .forType(Staff.class)
        .readValue(jsonInString);
      System.out.println(normalStaff);
      // Display everything
      System.out.println("\nManager View");
      String managerView = mapper
        .writerWithView(Views.Manager.class)
        .writeValueAsString(staff);
      System.out.println(managerView);
      Staff managerStaff = mapper
        .readerWithView(Views.Manager.class)
        .forType(Staff.class)
        .readValue(jsonInString);
      System.out.println(managerStaff);
    } catch (JsonGenerationException e) {
      e.printStackTrace();
    } catch (JsonMappingException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  private Staff createDummyObject() {
    Staff staff = new Staff();
    staff.setName("mkyong");
    staff.setAge(33);
    staff.setPosition("Developer");
    staff.setSalary(new BigDecimal("7500"));
    List<String> skills = new ArrayList<>();
    skills.add("java");
    skills.add("python");
    staff.setSkills(skills);
    return staff;
  }
}Copy to clipboardErrorCopied

最终输出的结果为:

Normal View
{"name":"mkyong","age":33,"position":"Developer","skills":["java","python"]}
Staff [name=mkyong, age=33, position=Developer, salary=null, skills=[java, python]]
Manager View
{"name":"mkyong","age":33,"position":"Developer","salary":7500,"skills":["java","python"]}
Staff [name=mkyong, age=33, position=Developer, salary=7500, skills=[java, python]]Copy to clipboardErrorCopied
下一节:Java 是面向对象的编程语言,有时需要保存对象,并在下次使用时可以顺利还原该对象。由于这种需求很常见,所以 Java API 对此提供了支持,添加相关程序代码到标准类库中,并将保存和还原的过程称之为“对象序列化”。Java SE7 文档中将与对象序列化的相关内容做了详细表述,将其称为: “Java 对象序列化规范”(Java Object Serialization Specification)。