Jackson Annotation Examples – Jackson注释的例子

最后修改: 2015年 6月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll do a deep dive into Jackson Annotations.

在本教程中,我们将对Jackson注释进行深入探讨。

We’ll see how to use the existing annotations, how to create custom ones, and finally, how to disable them.

我们将看到如何使用现有的注释,如何创建自定义的注释,最后是如何禁用它们。

2. Jackson Serialization Annotations

2.Jackson的序列化注释

First, we’ll take a look at the serialization annotations.

首先,我们要看一下序列化注释。

2.1. @JsonAnyGetter

2.1.@JsonAnyGetter

The @JsonAnyGetter annotation allows for the flexibility of using a Map field as standard properties.

@JsonAnyGetter注解允许灵活使用Map字段作为标准属性。

For example, the ExtendableBean entity has the name property and a set of extendable attributes in the form of key/value pairs:

例如,ExtendableBean实体有name属性和一组以键/值对形式存在的可扩展属性。

public class ExtendableBean {
    public String name;
    private Map<String, String> properties;

    @JsonAnyGetter
    public Map<String, String> getProperties() {
        return properties;
    }
}

When we serialize an instance of this entity, we get all the key-values in the Map as standard, plain properties:

当我们序列化这个实体的一个实例时,我们得到Map中的所有键值,作为标准的、普通的属性。

{
    "name":"My bean",
    "attr2":"val2",
    "attr1":"val1"
}

Here’s how the serialization of this entity looks in practice:

下面是这个实体的序列化在实践中的样子。

@Test
public void whenSerializingUsingJsonAnyGetter_thenCorrect()
  throws JsonProcessingException {
 
    ExtendableBean bean = new ExtendableBean("My bean");
    bean.add("attr1", "val1");
    bean.add("attr2", "val2");

    String result = new ObjectMapper().writeValueAsString(bean);
 
    assertThat(result, containsString("attr1"));
    assertThat(result, containsString("val1"));
}

We can also use the optional argument enabled as false to disable @JsonAnyGetter(). In this case, the Map will be converted as JSON and will appear under the properties variable after serialization.

我们也可以使用可选的参数enabled作为false来禁用@JsonAnyGetter()。在这种情况下,Map将被转换为JSON,在序列化后将出现在properties变量下。

2.2. @JsonGetter

2.2.@JsonGetter

The @JsonGetter annotation is an alternative to the @JsonProperty annotation, which marks a method as a getter method.

@JsonGetter注解是@JsonProperty注解的替代品,后者将一个方法标记为一个getter方法。

In the following example, we specify the method getTheName() as the getter method of the name property of a MyBean entity:

在下面的例子中,我们指定方法getTheName()作为MyBean实体的name属性的getter方法。

public class MyBean {
    public int id;
    private String name;

    @JsonGetter("name")
    public String getTheName() {
        return name;
    }
}

Here’s how this works in practice:

以下是这一做法的实际效果。

@Test
public void whenSerializingUsingJsonGetter_thenCorrect()
  throws JsonProcessingException {
 
    MyBean bean = new MyBean(1, "My bean");

    String result = new ObjectMapper().writeValueAsString(bean);
 
    assertThat(result, containsString("My bean"));
    assertThat(result, containsString("1"));
}

2.3. @JsonPropertyOrder

2.3.@JsonPropertyOrder

We can use the @JsonPropertyOrder annotation to specify the order of properties on serialization.

我们可以使用@JsonPropertyOrder注解来指定序列化时属性的顺序

Let’s set a custom order for the properties of a MyBean entity:

让我们为MyBean实体的属性设置一个自定义顺序。

@JsonPropertyOrder({ "name", "id" })
public class MyBean {
    public int id;
    public String name;
}

Here’s the output of serialization:

下面是序列化的输出。

{
    "name":"My bean",
    "id":1
}

Then we can do a simple test:

然后我们可以做一个简单的测试。

@Test
public void whenSerializingUsingJsonPropertyOrder_thenCorrect()
  throws JsonProcessingException {
 
    MyBean bean = new MyBean(1, "My bean");

    String result = new ObjectMapper().writeValueAsString(bean);
    assertThat(result, containsString("My bean"));
    assertThat(result, containsString("1"));
}

We can also use @JsonPropertyOrder(alphabetic=true) to order the properties alphabetically. In that case, the output of serialization will be:

我们也可以使用@JsonPropertyOrder(alphabetic=true)来按字母顺序排列属性。在这种情况下,序列化的输出将是。

{
    "id":1,
    "name":"My bean"
}

2.4. @JsonRawValue

2.4.@JsonRawValue

The @JsonRawValue annotation can instruct Jackson to serialize a property exactly as is.

@JsonRawValue注解可以指示Jackson完全按原样序列化一个属性

In the following example, we use @JsonRawValue to embed some custom JSON as a value of an entity:

在下面的例子中,我们使用@JsonRawValue来嵌入一些自定义的JSON作为一个实体的值。

public class RawBean {
    public String name;

    @JsonRawValue
    public String json;
}

The output of serializing the entity is:

对实体进行序列化的输出是。

{
    "name":"My bean",
    "json":{
        "attr":false
    }
}

Next here’s a simple test:

接下来这里有一个简单的测试。

@Test
public void whenSerializingUsingJsonRawValue_thenCorrect()
  throws JsonProcessingException {
 
    RawBean bean = new RawBean("My bean", "{\"attr\":false}");

    String result = new ObjectMapper().writeValueAsString(bean);
    assertThat(result, containsString("My bean"));
    assertThat(result, containsString("{\"attr\":false}"));
}

We can also use the optional boolean argument value that defines whether this annotation is active or not.

我们还可以使用可选的布尔参数value,它定义了这个注解是否被激活。

2.5. @JsonValue

2.5.@JsonValue

@JsonValue indicates a single method that the library will use to serialize the entire instance.

@JsonValue表示一个单一的方法,该库将用来序列化整个实例。

For example, in an enum, we annotate the getName with @JsonValue so that any such entity is serialized via its name:

例如,在一个枚举中,我们用@JsonValue来注解getName,这样任何这样的实体都会通过它的名字被序列化。

public enum TypeEnumWithValue {
    TYPE1(1, "Type A"), TYPE2(2, "Type 2");

    private Integer id;
    private String name;

    // standard constructors

    @JsonValue
    public String getName() {
        return name;
    }
}

Now here’s our test:

现在是我们的测试。

@Test
public void whenSerializingUsingJsonValue_thenCorrect()
  throws JsonParseException, IOException {
 
    String enumAsString = new ObjectMapper()
      .writeValueAsString(TypeEnumWithValue.TYPE1);

    assertThat(enumAsString, is(""Type A""));
}

2.6. @JsonRootName

2.6.@JsonRootName

The @JsonRootName annotation is used, if wrapping is enabled, to specify the name of the root wrapper to be used.

如果启用了包装,@JsonRootName注解被用来指定要使用的根包装器的名称。

Wrapping means that instead of serializing a User to something like:

包裹的意思是,不要把一个User序列化为类似的东西。

{
    "id": 1,
    "name": "John"
}

It’s going to be wrapped like this:

它要像这样包起来。

{
    "User": {
        "id": 1,
        "name": "John"
    }
}

So let’s look at an example. We’re going to use the @JsonRootName annotation to indicate the name of this potential wrapper entity:

那么,让我们看一个例子。W我们将使用@JsonRootName注解来表示这个潜在的包装实体的名称

@JsonRootName(value = "user")
public class UserWithRoot {
    public int id;
    public String name;
}

By default, the name of the wrapper would be the name of the class – UserWithRoot. By using the annotation, we get the cleaner looking user:

默认情况下,包装器的名字是类的名字–UserWithRoot。通过使用注解,我们得到了看起来更干净的user。

@Test
public void whenSerializingUsingJsonRootName_thenCorrect()
  throws JsonProcessingException {
 
    UserWithRoot user = new User(1, "John");

    ObjectMapper mapper = new ObjectMapper();
    mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
    String result = mapper.writeValueAsString(user);

    assertThat(result, containsString("John"));
    assertThat(result, containsString("user"));
}

Here’s the output of serialization:

下面是序列化的输出。

{
    "user":{
        "id":1,
        "name":"John"
    }
}

Since Jackson 2.4, a new optional argument namespace is available to use with data formats such as XML. If we add it, it will become part of the fully qualified name:

从Jackson 2.4开始,一个新的可选参数namespace可用于数据格式,如XML。如果我们添加它,它将成为完全限定名称的一部分。

@JsonRootName(value = "user", namespace="users")
public class UserWithRootNamespace {
    public int id;
    public String name;

    // ...
}

If we serialize it with XmlMapper, the output will be:

如果我们用XmlMapper将其序列化,输出将是。

<user xmlns="users">
    <id xmlns="">1</id>
    <name xmlns="">John</name>
    <items xmlns=""/>
</user>

2.7. @JsonSerialize

2.7.@JsonSerialize

@JsonSerialize indicates a custom serializer to use when marshalling the entity.

@JsonSerialize 表示一个自定义的序列化器,当marshalling实体时使用。

Let’s look at a quick example. We’re going to use @JsonSerialize to serialize the eventDate property with a CustomDateSerializer:

让我们看一个快速的例子。我们将使用@JsonSerialize,用CustomDateSerializer来序列化eventDate属性。

public class EventWithSerializer {
    public String name;

    @JsonSerialize(using = CustomDateSerializer.class)
    public Date eventDate;
}

Here’s the simple custom Jackson serializer:

这里是简单的自定义杰克逊序列化器。

public class CustomDateSerializer extends StdSerializer<Date> {

    private static SimpleDateFormat formatter 
      = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    public CustomDateSerializer() { 
        this(null); 
    } 

    public CustomDateSerializer(Class<Date> t) {
        super(t); 
    }

    @Override
    public void serialize(
      Date value, JsonGenerator gen, SerializerProvider arg2) 
      throws IOException, JsonProcessingException {
        gen.writeString(formatter.format(value));
    }
}

Now let’s use these in a test:

现在让我们在测试中使用这些。

@Test
public void whenSerializingUsingJsonSerialize_thenCorrect()
  throws JsonProcessingException, ParseException {
 
    SimpleDateFormat df
      = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    String toParse = "20-12-2014 02:30:00";
    Date date = df.parse(toParse);
    EventWithSerializer event = new EventWithSerializer("party", date);

    String result = new ObjectMapper().writeValueAsString(event);
    assertThat(result, containsString(toParse));
}

3. Jackson Deserialization Annotations

3.Jackson的反序列化注释

Next let’s explore the Jackson deserialization annotations.

接下来让我们探讨一下Jackson的反序列化注释。

3.1. @JsonCreator

3.1.@JsonCreator

We can use the @JsonCreator annotation to tune the constructor/factory used in deserialization.

我们可以使用 @JsonCreator注解来调整反序列化中使用的构造器/工厂。

It’s very useful when we need to deserialize some JSON that doesn’t exactly match the target entity we need to get.

当我们需要反序列化一些与我们需要得到的目标实体不完全匹配的JSON时,它非常有用。

Let’s look at an example. Say we need to deserialize the following JSON:

让我们看一个例子。假设我们需要对下面的JSON进行反序列化。

{
    "id":1,
    "theName":"My bean"
}

However, there is no theName field in our target entity, there is only a name field. Now we don’t want to change the entity itself, we just need a little more control over the unmarshalling process by annotating the constructor with @JsonCreator, and using the @JsonProperty annotation as well:

然而,在我们的目标实体中没有theName字段,只有一个name字段。现在我们不想改变实体本身,我们只需要通过用@JsonCreator,注解构造器,并使用@JsonProperty注解,对解调过程进行更多的控制。

public class BeanWithCreator {
    public int id;
    public String name;

    @JsonCreator
    public BeanWithCreator(
      @JsonProperty("id") int id, 
      @JsonProperty("theName") String name) {
        this.id = id;
        this.name = name;
    }
}

Let’s see this in action:

让我们看看这个行动。

@Test
public void whenDeserializingUsingJsonCreator_thenCorrect()
  throws IOException {
 
    String json = "{\"id\":1,\"theName\":\"My bean\"}";

    BeanWithCreator bean = new ObjectMapper()
      .readerFor(BeanWithCreator.class)
      .readValue(json);
    assertEquals("My bean", bean.name);
}

3.2. @JacksonInject

3.2.@JacksonInject

@JacksonInject indicates that a property will get its value from the injection and not from the JSON data.

@JacksonInject表示一个属性将从注入中获得其值,而不是从JSON数据中获得。

In the following example, we use @JacksonInject to inject the property id:

在下面的例子中,我们使用@JacksonInject来注入属性id

public class BeanWithInject {
    @JacksonInject
    public int id;
    
    public String name;
}

Here’s how it works:

以下是它的工作原理。

@Test
public void whenDeserializingUsingJsonInject_thenCorrect()
  throws IOException {
 
    String json = "{\"name\":\"My bean\"}";
    
    InjectableValues inject = new InjectableValues.Std()
      .addValue(int.class, 1);
    BeanWithInject bean = new ObjectMapper().reader(inject)
      .forType(BeanWithInject.class)
      .readValue(json);
    
    assertEquals("My bean", bean.name);
    assertEquals(1, bean.id);
}

3.3. @JsonAnySetter

3.3.@JsonAnySetter

@JsonAnySetter allows us the flexibility of using a Map as standard properties. On deserialization, the properties from JSON will simply be added to the map.

@JsonAnySetter允许我们灵活使用Map作为标准属性。在反序列化时,来自JSON的属性将被简单地添加到地图中。

First, we’ll use @JsonAnySetter to deserialize the entity ExtendableBean:

首先,我们将使用@JsonAnySetter来反序列化实体ExtendableBean

public class ExtendableBean {
    public String name;
    private Map<String, String> properties;

    @JsonAnySetter
    public void add(String key, String value) {
        properties.put(key, value);
    }
}

This is the JSON we need to deserialize:

这就是我们需要反序列化的JSON。

{
    "name":"My bean",
    "attr2":"val2",
    "attr1":"val1"
}

Then here’s how it all ties in together:

然后,这里是如何将这一切联系起来的。

@Test
public void whenDeserializingUsingJsonAnySetter_thenCorrect()
  throws IOException {
    String json
      = "{\"name\":\"My bean\",\"attr2\":\"val2\",\"attr1\":\"val1\"}";

    ExtendableBean bean = new ObjectMapper()
      .readerFor(ExtendableBean.class)
      .readValue(json);
    
    assertEquals("My bean", bean.name);
    assertEquals("val2", bean.getProperties().get("attr2"));
}

3.4. @JsonSetter

3.4.@JsonSetter

@JsonSetter is an alternative to @JsonProperty that marks the method as a setter method.

@JsonSetter@JsonProperty的替代品,它将方法标记为setter方法。

This is incredibly useful when we need to read some JSON data, but the target entity class doesn’t exactly match that data, and so we need to tune the process to make it fit.

当我们需要读取一些JSON数据,但目标实体类与该数据不完全匹配时,这是非常有用的,因此我们需要调整流程,使其适合。

In the following example, we’ll specify the method setTheName() as the setter of the name property in our MyBean entity:

在下面的例子中,我们将指定方法setTheName()作为我们MyBean实体中name属性的设置器。

public class MyBean {
    public int id;
    private String name;

    @JsonSetter("name")
    public void setTheName(String name) {
        this.name = name;
    }
}

Now when we need to unmarshall some JSON data, this works perfectly well:

现在,当我们需要解读一些JSON数据时,这可以很好地工作。

@Test
public void whenDeserializingUsingJsonSetter_thenCorrect()
  throws IOException {
 
    String json = "{\"id\":1,\"name\":\"My bean\"}";

    MyBean bean = new ObjectMapper()
      .readerFor(MyBean.class)
      .readValue(json);
    assertEquals("My bean", bean.getTheName());
}

3.5. @JsonDeserialize

3.5.@JsonDeserialize

@JsonDeserialize indicates the use of a custom deserializer.

@JsonDeserialize表示使用了一个自定义的反序列化器

First, we’ll use @JsonDeserialize to deserialize the eventDate property with the CustomDateDeserializer:

首先,我们将使用@JsonDeserialize来用CustomDateDeserializereventDate属性进行解串。

public class EventWithSerializer {
    public String name;

    @JsonDeserialize(using = CustomDateDeserializer.class)
    public Date eventDate;
}

Here’s the custom deserializer:

这里是自定义的反序列化器。

public class CustomDateDeserializer
  extends StdDeserializer<Date> {

    private static SimpleDateFormat formatter
      = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    public CustomDateDeserializer() { 
        this(null); 
    } 

    public CustomDateDeserializer(Class<?> vc) { 
        super(vc); 
    }

    @Override
    public Date deserialize(
      JsonParser jsonparser, DeserializationContext context) 
      throws IOException {
        
        String date = jsonparser.getText();
        try {
            return formatter.parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}

Next here’s the back-to-back test:

接下来是背对背的测试。

@Test
public void whenDeserializingUsingJsonDeserialize_thenCorrect()
  throws IOException {
 
    String json
      = "{"name":"party","eventDate":"20-12-2014 02:30:00"}";

    SimpleDateFormat df
      = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
    EventWithSerializer event = new ObjectMapper()
      .readerFor(EventWithSerializer.class)
      .readValue(json);
    
    assertEquals(
      "20-12-2014 02:30:00", df.format(event.eventDate));
}

3.6. @JsonAlias

3.6 @JsonAlias

The @JsonAlias defines one or more alternative names for a property during deserialization.

@JsonAlias定义了在反序列化过程中属性的一个或多个替代名称

Let’s see how this annotation works with a quick example:

让我们通过一个快速的例子来看看这个注释是如何工作的。

public class AliasBean {
    @JsonAlias({ "fName", "f_name" })
    private String firstName;   
    private String lastName;
}

Here we have a POJO, and we want to deserialize JSON with values such as fName, f_name, and firstName into the firstName variable of the POJO.

在这里,我们有一个POJO,我们想把带有fNamef_namefirstName等值的JSON反序列化到POJO的firstName变量。

Below is a test making sure this annotation works as expected:

下面是一个测试,以确保这个注解按预期工作。

@Test
public void whenDeserializingUsingJsonAlias_thenCorrect() throws IOException {
    String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}";
    AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json);
    assertEquals("John", aliasBean.getFirstName());
}

4. Jackson Property Inclusion Annotations

4.Jackson属性的包容注释

4.1. @JsonIgnoreProperties

4.1.@JsonIgnoreProperties

@JsonIgnoreProperties is a class-level annotation that marks a property or a list of properties that Jackson will ignore.

@JsonIgnoreProperties是一个类级注解,用于标记Jackson将忽略的一个属性或一个属性列表。

Let’s look at a quick example ignoring the property id from serialization:

让我们看一个快速的例子,从序列化中忽略属性id

@JsonIgnoreProperties({ "id" })
public class BeanWithIgnore {
    public int id;
    public String name;
}

Now here’s the test making sure the ignore happens:

现在是测试,确保忽略的发生。

@Test
public void whenSerializingUsingJsonIgnoreProperties_thenCorrect()
  throws JsonProcessingException {
 
    BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");

    String result = new ObjectMapper()
      .writeValueAsString(bean);
    
    assertThat(result, containsString("My bean"));
    assertThat(result, not(containsString("id")));
}

To ignore any unknown properties in JSON input without exception, we can set ignoreUnknown=true of @JsonIgnoreProperties annotation.

要无例外地忽略JSON输入中的任何未知属性,我们可以设置@JsonIgnoreProperties 注释的ignoreUnknown=true

4.2. @JsonIgnore

4.2.@JsonIgnore

In contrast, the @JsonIgnore annotation is used to mark a property to be ignored at the field level.

相比之下, @JsonIgnore注解被用来标记一个在字段级别被忽略的属性。

Let’s use @JsonIgnore to ignore the property id from serialization:

让我们使用@JsonIgnore来忽略序列化中的属性id

public class BeanWithIgnore {
    @JsonIgnore
    public int id;

    public String name;
}

Then we’ll test to make sure that id was successfully ignored:

然后我们将测试以确保id被成功忽略。

@Test
public void whenSerializingUsingJsonIgnore_thenCorrect()
  throws JsonProcessingException {
 
    BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");

    String result = new ObjectMapper()
      .writeValueAsString(bean);
    
    assertThat(result, containsString("My bean"));
    assertThat(result, not(containsString("id")));
}

4.3. @JsonIgnoreType

4.3. @JsonIgnoreType

@JsonIgnoreType marks all properties of an annotated type to be ignored.

@JsonIgnoreType标志着一个被注释的类型的所有属性被忽略。

We can use the annotation to mark all properties of type Name to be ignored:

我们可以使用注解来标记所有类型为Name的属性被忽略。

public class User {
    public int id;
    public Name name;

    @JsonIgnoreType
    public static class Name {
        public String firstName;
        public String lastName;
    }
}

We can also test to ensure the ignore works correctly:

我们还可以进行测试,以确保忽略的工作正常。

@Test
public void whenSerializingUsingJsonIgnoreType_thenCorrect()
  throws JsonProcessingException, ParseException {
 
    User.Name name = new User.Name("John", "Doe");
    User user = new User(1, name);

    String result = new ObjectMapper()
      .writeValueAsString(user);

    assertThat(result, containsString("1"));
    assertThat(result, not(containsString("name")));
    assertThat(result, not(containsString("John")));
}

4.4. @JsonInclude

4.4.@JsonInclude

We can use @JsonInclude to exclude properties with empty/null/default values.

我们可以使用@JsonInclude来排除具有空/无/默认值的属性。

Let’s look at an example excluding nulls from serialization:

让我们看一个从序列化中排除空值的例子。

@JsonInclude(Include.NON_NULL)
public class MyBean {
    public int id;
    public String name;
}

Here’s the full test:

下面是完整的测试。

public void whenSerializingUsingJsonInclude_thenCorrect()
  throws JsonProcessingException {
 
    MyBean bean = new MyBean(1, null);

    String result = new ObjectMapper()
      .writeValueAsString(bean);
    
    assertThat(result, containsString("1"));
    assertThat(result, not(containsString("name")));
}

4.5. @JsonAutoDetect

4.5.@JsonAutoDetect

@JsonAutoDetect can override the default semantics of which properties are visible and which are not.

@JsonAutoDetect可以覆盖哪些属性是可见的,哪些是不可见的的默认语义。

First, let’s take a look at how the annotation can be very helpful with a simple example; let’s enable serializing private properties:

首先,让我们通过一个简单的例子来看看注解是如何发挥巨大作用的;让我们来启用序列化私有属性。

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class PrivateBean {
    private int id;
    private String name;
}

Then the test:

然后是测试。

@Test
public void whenSerializingUsingJsonAutoDetect_thenCorrect()
  throws JsonProcessingException {
 
    PrivateBean bean = new PrivateBean(1, "My bean");

    String result = new ObjectMapper()
      .writeValueAsString(bean);
    
    assertThat(result, containsString("1"));
    assertThat(result, containsString("My bean"));
}

5. Jackson Polymorphic Type Handling Annotations

5.Jackson的多态类型处理注释

Next let’s take a look at Jackson polymorphic type handling annotations:

接下来让我们看看杰克逊的多态类型处理注释。

  • @JsonTypeInfo – indicates details of what type information to include in serialization
  • @JsonSubTypes – indicates sub-types of the annotated type
  • @JsonTypeName – defines a logical type name to use for annotated class

Let’s examine a more complex example, and use all three – @JsonTypeInfo, @JsonSubTypes, and @JsonTypeName – to serialize/deserialize the entity Zoo:

让我们来看看一个更复杂的例子,并使用所有三个–@JsonTypeInfo@JsonSubTypes、@JsonTypeName–来序列化/反序列化实体Zoo

public class Zoo {
    public Animal animal;

    @JsonTypeInfo(
      use = JsonTypeInfo.Id.NAME, 
      include = As.PROPERTY, 
      property = "type")
    @JsonSubTypes({
        @JsonSubTypes.Type(value = Dog.class, name = "dog"),
        @JsonSubTypes.Type(value = Cat.class, name = "cat")
    })
    public static class Animal {
        public String name;
    }

    @JsonTypeName("dog")
    public static class Dog extends Animal {
        public double barkVolume;
    }

    @JsonTypeName("cat")
    public static class Cat extends Animal {
        boolean likesCream;
        public int lives;
    }
}

When we do serialization:

当我们做序列化的时候。

@Test
public void whenSerializingPolymorphic_thenCorrect()
  throws JsonProcessingException {
    Zoo.Dog dog = new Zoo.Dog("lacy");
    Zoo zoo = new Zoo(dog);

    String result = new ObjectMapper()
      .writeValueAsString(zoo);

    assertThat(result, containsString("type"));
    assertThat(result, containsString("dog"));
}

Here’s what serializing the Zoo instance with the Dog will result in:

下面是将Zoo实例与Dog序列化后的结果。

{
    "animal": {
        "type": "dog",
        "name": "lacy",
        "barkVolume": 0
    }
}

Now for de-serialization. Let’s start with the following JSON input:

现在是去序列化。让我们从下面的JSON输入开始。

{
    "animal":{
        "name":"lacy",
        "type":"cat"
    }
}

Then let’s see how that gets unmarshalled to a Zoo instance:

然后让我们看看如何将其解调到一个Zoo实例。

@Test
public void whenDeserializingPolymorphic_thenCorrect()
throws IOException {
    String json = "{\"animal\":{\"name\":\"lacy\",\"type\":\"cat\"}}";

    Zoo zoo = new ObjectMapper()
      .readerFor(Zoo.class)
      .readValue(json);

    assertEquals("lacy", zoo.animal.name);
    assertEquals(Zoo.Cat.class, zoo.animal.getClass());
}

6. Jackson General Annotations

6.Jackson的一般注释

Next let’s discuss some of Jackson’s more general annotations.

接下来让我们讨论一下杰克逊的一些更一般的注释。

6.1. @JsonProperty

6.1.@JsonProperty

We can add the @JsonProperty annotation to indicate the property name in JSON.

我们可以添加 @JsonProperty注解来表明JSON中的属性名称

Let’s use @JsonProperty to serialize/deserialize the property name when we’re dealing with non-standard getters and setters:

当我们处理非标准的getters和setters时,让我们使用@JsonProperty来序列化/反序列化属性name

public class MyBean {
    public int id;
    private String name;

    @JsonProperty("name")
    public void setTheName(String name) {
        this.name = name;
    }

    @JsonProperty("name")
    public String getTheName() {
        return name;
    }
}

Next is our test:

接下来是我们的测试。

@Test
public void whenUsingJsonProperty_thenCorrect()
  throws IOException {
    MyBean bean = new MyBean(1, "My bean");

    String result = new ObjectMapper().writeValueAsString(bean);
    
    assertThat(result, containsString("My bean"));
    assertThat(result, containsString("1"));

    MyBean resultBean = new ObjectMapper()
      .readerFor(MyBean.class)
      .readValue(result);
    assertEquals("My bean", resultBean.getTheName());
}

6.2. @JsonFormat

6.2.@JsonFormat

The @JsonFormat annotation specifies a format when serializing Date/Time values.

@JsonFormat注解在序列化日期/时间值时指定了一种格式。

In the following example, we use @JsonFormat to control the format of the property eventDate:

在下面的例子中,我们使用@JsonFormat来控制属性eventDate的格式。

public class EventWithFormat {
    public String name;

    @JsonFormat(
      shape = JsonFormat.Shape.STRING,
      pattern = "dd-MM-yyyy hh:mm:ss")
    public Date eventDate;
}

Then here’s the test:

然后,这里有一个测试。

@Test
public void whenSerializingUsingJsonFormat_thenCorrect()
  throws JsonProcessingException, ParseException {
    SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
    df.setTimeZone(TimeZone.getTimeZone("UTC"));

    String toParse = "20-12-2014 02:30:00";
    Date date = df.parse(toParse);
    EventWithFormat event = new EventWithFormat("party", date);
    
    String result = new ObjectMapper().writeValueAsString(event);
    
    assertThat(result, containsString(toParse));
}

6.3. @JsonUnwrapped

6.3.@JsonUnwrapped

@JsonUnwrapped defines values that should be unwrapped/flattened when serialized/deserialized.

@JsonUnwrapped定义了在序列化/反序列化时应该被解包/扁平化的值。

Let’s see exactly how this works; we’ll use the annotation to unwrap the property name:

让我们看看这到底是如何工作的;我们将使用注解来解除属性name的包装。

public class UnwrappedUser {
    public int id;

    @JsonUnwrapped
    public Name name;

    public static class Name {
        public String firstName;
        public String lastName;
    }
}

Now let’s serialize an instance of this class:

现在让我们来序列化这个类的一个实例。

@Test
public void whenSerializingUsingJsonUnwrapped_thenCorrect()
  throws JsonProcessingException, ParseException {
    UnwrappedUser.Name name = new UnwrappedUser.Name("John", "Doe");
    UnwrappedUser user = new UnwrappedUser(1, name);

    String result = new ObjectMapper().writeValueAsString(user);
    
    assertThat(result, containsString("John"));
    assertThat(result, not(containsString("name")));
}

Finally, here’s what the output looks like – the fields of the static nested class unwrapped along with the other field:

最后,这是输出结果的样子–静态嵌套类的字段与其他字段一起被解开。

{
    "id":1,
    "firstName":"John",
    "lastName":"Doe"
}

6.4. @JsonView

6.4.@JsonView

@JsonView indicates the View in which the property will be included for serialization/deserialization.

@JsonView表示该属性将被包含在其中进行序列化/反序列化的视图。

For example, we’ll use @JsonView to serialize an instance of Item entity.

例如,我们将使用@JsonView来序列化一个Item实体的实例。

First, let’s start with the views:

首先,让我们从观点开始。

public class Views {
    public static class Public {}
    public static class Internal extends Public {}
}

Next here’s the Item entity using the views:

接下来这里是使用视图的Item实体。

public class Item {
    @JsonView(Views.Public.class)
    public int id;

    @JsonView(Views.Public.class)
    public String itemName;

    @JsonView(Views.Internal.class)
    public String ownerName;
}

Finally, the full test:

最后,全面测试。

@Test
public void whenSerializingUsingJsonView_thenCorrect()
  throws JsonProcessingException {
    Item item = new Item(2, "book", "John");

    String result = new ObjectMapper()
      .writerWithView(Views.Public.class)
      .writeValueAsString(item);

    assertThat(result, containsString("book"));
    assertThat(result, containsString("2"));
    assertThat(result, not(containsString("John")));
}

6.5. @JsonManagedReference, @JsonBackReference

6.5.@JsonManagedReference, @JsonBackReference

The @JsonManagedReference and @JsonBackReference annotations can handle parent/child relationships and work around loops.

@JsonManagedReference@JsonBackReference注解可以处理父/子关系并围绕循环进行工作。

In the following example, we use @JsonManagedReference and @JsonBackReference to serialize our ItemWithRef entity:

在下面的例子中,我们使用@JsonManagedReference@JsonBackReference来序列化我们的ItemWithRef实体。

public class ItemWithRef {
    public int id;
    public String itemName;

    @JsonManagedReference
    public UserWithRef owner;
}

Our UserWithRef entity:

我们的UserWithRef实体。

public class UserWithRef {
    public int id;
    public String name;

    @JsonBackReference
    public List<ItemWithRef> userItems;
}

Then the test:

然后是测试。

@Test
public void whenSerializingUsingJacksonReferenceAnnotation_thenCorrect()
  throws JsonProcessingException {
    UserWithRef user = new UserWithRef(1, "John");
    ItemWithRef item = new ItemWithRef(2, "book", user);
    user.addItem(item);

    String result = new ObjectMapper().writeValueAsString(item);

    assertThat(result, containsString("book"));
    assertThat(result, containsString("John"));
    assertThat(result, not(containsString("userItems")));
}

6.6. @JsonIdentityInfo

6.6.@JsonIdentityInfo

@JsonIdentityInfo indicates that Object Identity should be used when serializing/deserializing values, like when dealing with infinite recursion types of problems, for instance.

@JsonIdentityInfo 表示在序列化/反序列化值时应该使用对象身份,例如在处理无限递归类型的问题时。

In the following example, we have an ItemWithIdentity entity with a bidirectional relationship with the UserWithIdentity entity:

在下面的例子中,我们有一个ItemWithIdentity实体,与UserWithIdentity实体有双向的关系。

@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class,
  property = "id")
public class ItemWithIdentity {
    public int id;
    public String itemName;
    public UserWithIdentity owner;
}

The UserWithIdentity entity:

UserWithIdentity实体。

@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class,
  property = "id")
public class UserWithIdentity {
    public int id;
    public String name;
    public List<ItemWithIdentity> userItems;
}

Now let’s see how the infinite recursion problem is handled:

现在让我们看看如何处理无限递归问题

@Test
public void whenSerializingUsingJsonIdentityInfo_thenCorrect()
  throws JsonProcessingException {
    UserWithIdentity user = new UserWithIdentity(1, "John");
    ItemWithIdentity item = new ItemWithIdentity(2, "book", user);
    user.addItem(item);

    String result = new ObjectMapper().writeValueAsString(item);

    assertThat(result, containsString("book"));
    assertThat(result, containsString("John"));
    assertThat(result, containsString("userItems"));
}

Here’s the full output of the serialized item and user:

下面是序列化的项目和用户的完整输出。

{
    "id": 2,
    "itemName": "book",
    "owner": {
        "id": 1,
        "name": "John",
        "userItems": [
            2
        ]
    }
}

6.7. @JsonFilter

6.7.@JsonFilter

The @JsonFilter annotation specifies a filter to use during serialization.

@JsonFilter注解指定了一个在序列化过程中使用的过滤器。

First, we define the entity and we point to the filter:

首先,我们定义实体,并指向过滤器。

@JsonFilter("myFilter")
public class BeanWithFilter {
    public int id;
    public String name;
}

Now in the full test, we define the filter, which excludes all other properties except name from serialization:

现在在完整的测试中,我们定义了过滤器,它从序列化中排除了除name之外的所有其他属性。

@Test
public void whenSerializingUsingJsonFilter_thenCorrect()
  throws JsonProcessingException {
    BeanWithFilter bean = new BeanWithFilter(1, "My bean");

    FilterProvider filters 
      = new SimpleFilterProvider().addFilter(
        "myFilter", 
        SimpleBeanPropertyFilter.filterOutAllExcept("name"));

    String result = new ObjectMapper()
      .writer(filters)
      .writeValueAsString(bean);

    assertThat(result, containsString("My bean"));
    assertThat(result, not(containsString("id")));
}

7. Custom Jackson Annotation

7.自定义Jackson的注释

Next let’s see how to create a custom Jackson annotation. We can make use of the @JacksonAnnotationsInside annotation:

接下来让我们看看如何创建一个自定义的Jackson注解。我们可以利用@JacksonAnnotationsInside注释:

@Retention(RetentionPolicy.RUNTIME)
    @JacksonAnnotationsInside
    @JsonInclude(Include.NON_NULL)
    @JsonPropertyOrder({ "name", "id", "dateCreated" })
    public @interface CustomAnnotation {}

Now if we use the new annotation on an entity:

现在,如果我们在一个实体上使用新注解。

@CustomAnnotation
public class BeanWithCustomAnnotation {
    public int id;
    public String name;
    public Date dateCreated;
}

We can see how it combines the existing annotations into a simple custom one that we can use as a shorthand:

我们可以看到它是如何将现有的注释组合成一个简单的自定义注释,我们可以将其作为一个速记。

@Test
public void whenSerializingUsingCustomAnnotation_thenCorrect()
  throws JsonProcessingException {
    BeanWithCustomAnnotation bean 
      = new BeanWithCustomAnnotation(1, "My bean", null);

    String result = new ObjectMapper().writeValueAsString(bean);

    assertThat(result, containsString("My bean"));
    assertThat(result, containsString("1"));
    assertThat(result, not(containsString("dateCreated")));
}

The output of the serialization process:

序列化过程的输出。

{
    "name":"My bean",
    "id":1
}

8. Jackson MixIn Annotations

8.Jackson MixIn Annotations

Next let’s see how to use Jackson MixIn annotations.

接下来让我们看看如何使用Jackson MixIn注释。

For example, let’s use the MixIn annotations to ignore properties of type User:

例如,让我们使用MixIn注解来忽略User类型的属性。

public class Item {
    public int id;
    public String itemName;
    public User owner;
}
@JsonIgnoreType
public class MyMixInForIgnoreType {}

Then let’s see this in action:

然后让我们看看这个行动。

@Test
public void whenSerializingUsingMixInAnnotation_thenCorrect() 
  throws JsonProcessingException {
    Item item = new Item(1, "book", null);

    String result = new ObjectMapper().writeValueAsString(item);
    assertThat(result, containsString("owner"));

    ObjectMapper mapper = new ObjectMapper();
    mapper.addMixIn(User.class, MyMixInForIgnoreType.class);

    result = mapper.writeValueAsString(item);
    assertThat(result, not(containsString("owner")));
}

9. Disable Jackson Annotation

9.禁用Jackson注释

Finally, let’s see how we can disable all Jackson annotations. We can do this by disabling the MapperFeature.USE_ANNOTATIONS as in the following example:

最后,让我们看看如何禁用所有杰克逊注解。我们可以通过禁用MapperFeature.USE_ANNOTATIONS来做到这一点,如下面的例子。

@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
    public int id;
    public String name;
}

Now, after disabling annotations, these should have no effect and the defaults of the library should apply:

现在,在禁用注释后,这些应该没有效果,库的默认值应该适用。

@Test
public void whenDisablingAllAnnotations_thenAllDisabled()
  throws IOException {
    MyBean bean = new MyBean(1, null);

    ObjectMapper mapper = new ObjectMapper();
    mapper.disable(MapperFeature.USE_ANNOTATIONS);
    String result = mapper.writeValueAsString(bean);
    
    assertThat(result, containsString("1"));
    assertThat(result, containsString("name"));
}

The result of serialization before disabling annotations:

禁用注解前的序列化结果。

{"id":1}

The result of serialization after disabling annotations:

禁用注解后的序列化结果。

{
    "id":1,
    "name":null
}

10. Conclusion

10.结论

In this article, we examined Jackson annotations, just scratching the surface of the kind of flexibility we can get by using them correctly.

在这篇文章中,我们研究了杰克逊注释,只是对正确使用它们所能获得的那种灵活性进行了简单的分析。

The implementation of all of these examples and code snippets can be found over on GitHub.

所有这些例子和代码片断的实现都可以在GitHub上找到over