Jackson注解使用示例

1 概述

在本文中,我们将深入探讨Jackson注解。
我们将看到如何使用Jackson现有的注解,如何创建自定义注解以及如何禁用它们。

2 Jackson序列化注解

2.1 @JsonAnyGetter

@JsonAnyGetter注解提供了将Map字段转换为标准属性的灵活性。这是一个简单的示例– ExtendableBean实体具有name属性和一组以K/V对形式的可扩展属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ExtendableBean {
public String name;
private Map<String, String> properties;

public ExtendableBean() {
properties = new HashMap<String, String>();
}

public ExtendableBean(final String name) {
this.name = name;
properties = new HashMap<String, String>();
}

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

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

序列化此实体的实例时,我们将Map中的所有键值作为标准的纯属性获取,如下:

1
2
3
4
5
{
"name":"My bean",
"attr2":"val2",
"attr1":"val1"
}

测试:

1
2
3
4
5
6
7
8
9
@Test
public void whenSerializingUsingJsonAnyGetter_thenCorrect() throws JsonProcessingException {
final ExtendableBean bean = new ExtendableBean("My bean");
bean.add("attr1", "val1");
bean.add("attr2", "val2");

String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result);
}

我们还可以使用启用为false的可选参数来禁用@JsonAnyGetter()。在这种情况下,地图将转换为JSON,并在序列化后显示在properties变量下。{"name":"My bean","properties":{"attr2":"val2","attr1":"val1"}}

2.2 @JsonGetter

@JsonGetter注解是@JsonProperty注解的替代方法,用于将方法标记为getter方法。

在以下示例中,我们将方法getTheName()指定为MyBean实体的name属性的getter方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MyBean {
private int id;
private String name;

public MyBean() {

}

public MyBean(final int id, final String name) {
this.id = id;
this.name = name;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

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

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

测试:

1
2
3
4
5
6
7
8
9
10
11
    @Test
public void whenSerializingUsingJsonGetter_thenCorrect()
throws JsonProcessingException {

MyBean bean = new MyBean(1, "My bean");

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

System.out.println(result);
}
// {"id":1,"name":"My bean"}

因为这里name属性是私有的,且get和set方法名不是使用get/set+属性名。而jackson在序列化的时候,如果是私有属性会调用它的get方法,默认的get方法名就是get+属性名。如果不使用@JsonGetter注解指定,jackson会认为theName是一个属性。输出如下:
{"id":1,"theName":"My bean"}

2.3 @JsonPropertyOrder

我们可以使用@JsonPropertyOrder注解指定序列化属性的顺序。让我们为MyBean实体的属性设置自定义顺序:

1
2
3
4
5
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
public int id;
public String name;
}

测试输出如下:
{"name":"My bean","id":1}
我们还可以使用@JsonPropertyOrder(alphabetic = true)按字母顺序对属性进行排序。在这种情况下,序列化的输出将是:{"id":1,"name":"My bean"}

2.4 @JsonRawValue

@JsonRawValue注解可以使Jackson完全按原样序列化属性。

在以下示例中,我们使用@JsonRawValue嵌入一些自定义JSON作为实体的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class RawBean {
public String name;

@JsonRawValue
public String json;

public RawBean() {}

public RawBean(final String name, final String json) {
this.name = name;
this.json = json;
}
}

测试:

1
2
3
4
5
6
7
8
9
10
11
    @Test
public void whenSerializingUsingJsonRawValue_thenCorrect() throws JsonProcessingException {
final RawBean bean = new RawBean("My bean", "{\"attr\":false}");

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

System.out.println(result);
}
// {"name":"My bean","json":{"attr":false}}

// 如果不加@JsonRawValue注解;输出为:{"name":"My bean","json":"{\"attr\":false}"}

我们还可以使用可选的布尔参数值(value)来定义此注解是否起作用。

2.5 @JsonValue

@JsonValue注解的作用是告诉jackson序列化类实例时使用它标注的的单个方法。

例如,在一个枚举中,我们用@JsonValue注释getName,以便任何这样的实体都通过其名称序列化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public enum TypeEnumWithValue {
TYPE1(1, "Type A"),
TYPE2(2, "Type 2");

private Integer id;
private String name;

TypeEnumWithValue(Integer id, String name) {
this.id = id;
this.name = name;
}

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

测试:

1
2
3
4
5
6
7
8
9
10
11
    @Test
public void whenSerializingUsingJsonValue_thenCorrect()
throws JsonParseException, IOException {

String enumAsString = new ObjectMapper()
.writeValueAsString(TypeEnumWithValue.TYPE1);

System.out.println(enumAsString);

}
// "Type A"

如果不使用@JsonValue标记,枚举序列化出来的是"TYPE1"

2.6 @JsonRootName

@JsonRootName的作用可以理解为,在序列化好的json串外面再包裹一层。
假设之前我们的序列化之后是这样的:

1
2
3
4
5
> {
> "id": 1,
> "name": "John"
> }
>

使用@JsonRootName包裹一层会变成这样

1
2
3
4
5
6
7
> {
> "user": {
> "id": 1,
> "name": "John"
> }
> }
>

看一下如何使用:

1
2
3
4
5
@JsonRootName(value = "user")
public class UserWithRoot {
public int id;
public String name;
}

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

1
2
3
4
5
6
7
@JsonRootName(value = "user", namespace="users")
public class UserWithRootNamespace {
public int id;
public String name;

// ...
}

xml效果是这样的

1
2
3
4
5
<user xmlns="users">
<id xmlns="">1</id>
<name xmlns="">John</name>
<items xmlns=""/>
</user>

2.7 @JsonSerialize

@JsonSerialize表示在序列化实体时要使用的自定义序列化程序。

让我们看一个简单的例子。我们将使用@JsonSerialize通过CustomDateSerializer来序列化eventDate属性:

1
2
3
4
5
6
public class EventWithSerializer {
public String name;

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

这是简单的自定义Jackson序列化器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class CustomDateSerializer extends StdSerializer<Date> {
private static final long serialVersionUID = -2894356342227378312L;

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

public CustomDateSerializer() {
this(null);
}

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

@Override
public void serialize(Date date,
JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(formatter.format(date));
}
}

让我们测试下:

1
2
3
4
5
6
7
8
9
10
11
    @Test
public void whenSerializingUsingJsonSerialize_thenCorrect()
throws JsonProcessingException {

Date date = new Date();
EventWithSerializer event = new EventWithSerializer("party", date);

String result = new ObjectMapper().writeValueAsString(event);
System.out.println(result);
}
// {"name":"party","eventDate":"24-02-2020 02:34:26"}

3 Jackson反序列化注解

3.1 @JsonCreator

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

当我们需要反序列化某些与我们需要获取的目标实体不完全匹配的JSON时,这非常有用。
让我们看一个例子;假设我们需要反序列化的JSON如下:

1
2
3
4
{
"id":1,
"theName":"My bean"
}

但是,我们的目标实体中没有theName字段,只有一个name字段。现在,我们不想更改实体本身,我们只需要对解组过程进行更多控制,通过使用@JsonCreator注释构造函数并同时使用@JsonProperty注释:

1
2
3
4
5
6
7
8
9
10
11
12
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;
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
    @Test
public void whenDeserializingUsingJsonCreator_thenCorrect()
throws IOException {

String json = "{\"id\":1,\"theName\":\"My bean\"}";

BeanWithCreator bean = new ObjectMapper()
.readerFor(BeanWithCreator.class)
.readValue(json);
System.out.println(bean.name);
}
// My bean
// 如果不使用,会报错。

3.2 @JacksonInject

@JacksonInject表示该属性将从注入中获取而不是从JSON数据获取其值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BeanWithInject {
@JacksonInject
public int id;
public String name;

public BeanWithInject() {

}

public BeanWithInject(final int id, final String name) {
this.id = id;
this.name = name;
}
}

测试如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    @Test
public void whenDeserializingUsingJsonInject_thenCorrect()
throws IOException {

String json = "{\"name\":\"My bean\"}";

// 使用jackson的InjectableValues类进行注入
InjectableValues inject = new InjectableValues.Std()
.addValue(int.class, 1);

BeanWithInject bean = new ObjectMapper()
.reader(inject)
.forType(BeanWithInject.class)
.readValue(json);

System.out.println(bean);
}
// BeanWithInject{id=1, name='My bean'}

3.3 @JsonAnySetter

@JsonAnySetter使我们可以灵活地使用Map作为标准属性。反序列化时,JSON的属性将简单地添加到地图中。和之前介绍的@JsonAnyGetter正好相反。

1
2
3
4
5
6
7
8
9
public class ExtendableBean {
public String name;
private Map<String, String> properties;

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

假设我们的json是这样的:

1
2
3
4
5
{
"name":"My bean",
"attr2":"val2",
"attr1":"val1"
}

那么attr2attr1会注入到Map中。

3.4 @JsonSetter

和之前介绍的@JsonGetter相反,不做过多介绍。

3.5 @JsonDeserialize

这个是用来指定自定义的反序列化规则的。

让我们来看一个例子,我们将使用@JsonDeserialize与CustomDateDeserializer反序列化eventDate属性:

1
2
3
4
5
6
7
public class EventWithSerializer {
public String name;

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

自定义的反序列化器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class CustomDateDeserializer extends StdDeserializer<Date> {

private static final long serialVersionUID = -5451717385630622729L;

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

public CustomDateDeserializer() {
this(null);
}

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


@Override
public Date deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
final String date = jsonParser.getText();
try {
return formatter.parse(date);
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
    @Test
public void whenDeserializingUsingJsonDeserialize_thenCorrect()
throws IOException {

String json = "{\"name\":\"party\",\"eventDate\":\"02-02-2020 02:30:00\"}";

EventWithSerializer event = new ObjectMapper()
.readerFor(EventWithSerializer.class)
.readValue(json);

System.out.println(event);
}
// EventWithSerializer{name='party', eventDate=Sun Feb 02 02:30:00 CST 2020}

3.6 @JsonAlias

@JsonAlias在反序列化期间为属性定义一个或多个备用名称。

让我们用一个简单的例子看看这个注解是如何工作的:

1
2
3
4
5
public class AliasBean {
@JsonAlias({ "fName", "f_name" })
private String firstName;
private String lastName;
}

在这里,我们有一个POJO,我们想将JSON中的fName、f_name或firstName属性的值反序列化到POJO的firstName变量中。
测试如下:

1
2
3
4
5
6
7
8
9
    @Test
public void whenDeserializingUsingJsonAlias_thenCorrect() throws IOException {
String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}";

AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json);

System.out.println(aliasBean);
}
// AliasBean{firstName='John', lastName='Green'}

4 Jackson属性包含注解

4.1 @JsonIgnoreProperties

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

让我们看一个简单的示例,忽略序列化中的属性ID:

1
2
3
4
5
@JsonIgnoreProperties({ "id" })
public class BeanWithIgnore {
public int id;
public String name;
}

4.2 @JsonIgnore

@JsonIgnore批注用于在字段级别标记要忽略的属性。

1
2
3
4
5
6
public class BeanWithIgnore {
@JsonIgnore
public int id;

public String name;
}

4.3 @JsonIgnoreType

@JsonIgnoreType将带注解类的所有属性标记为忽略。

1
2
3
4
5
6
7
8
9
10
public class User {
public int id;
public Name name;

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

4.4 @JsonInclude

我们可以使用@JsonInclude排除具有empty/null/default values的属性。

1
2
3
4
5
6
// 从序列化中排除空值:
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MyBean {
public int id;
public String name;
}

4.5 @JsonAutoDetect

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

让我们来看一个简单的示例,该注解如何帮助我们让私有属性可序列化:

1
2
3
4
5
6
7
8
9
10
11
12
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class PrivateBean {
private int id;
private String name;

public PrivateBean() {}

public PrivateBean(final int id, final String name) {
this.id = id;
this.name = name;
}
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
    @Test
public void whenSerializingUsingJsonAutoDetect_thenCorrect()
throws JsonProcessingException {

PrivateBean bean = new PrivateBean(1, "My bean");

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

System.out.println(result);
}
// {"id":1,"name":"My bean"}

这样,私有属性没有get方法也可以被序列化了。

5 Jackson多态类型处理注解

接下来–让我们看一下Jackson的多态类型处理注释:

  • @JsonTypeInfo - 指示要在序列化中包含哪些类型信息的详细信息
  • @JsonSubTypes - 指示带注解类型的子类型
  • @JsonTypeName - 定义用于注解类的逻辑类型名称

让我们看一个复杂的示例,使用@JsonTypeInfo,@ JsonSubTypes@JsonTypeName三个注解序列化和反序列化实体Zoo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class Zoo {

public Animal animal;

public Zoo() {}

public Zoo(final Animal animal) {
this.animal = animal;
}


/***********************以下是三个静态内部类*********************/


public static class Animal {
public String name;

public Animal() {}

public Animal(final String name) {
this.name = name;
}
}
public static class Dog extends Animal {
public double barkVolume;

public Dog() {}

public Dog(final String name) {
this.name = name;
}
}

public static class Cat extends Animal {
boolean likesCream;
public int lives;

public Cat() {}

public Cat(final String name) {
this.name = name;
}
}
}

以上我们什么注解都没有加,看序列化后是什么结果

1
2
3
4
5
6
7
8
9
10
11
12
    @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);

System.out.println(result);
}
// {"animal":{"name":"lacy","barkVolume":0.0}}

这样序列化后,我们只知道是一个动物,却不知道具体是什么动物,下面我们就利用以上三个注解进行修饰下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.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;

public Animal() {}

public Animal(final String name) {
this.name = name;
}
}

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

public Dog() {}

public Dog(final String name) {
this.name = name;
}
}

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

public Cat() {}

public Cat(final String name) {
this.name = name;
}
}

我们在Animal类上加上以上注解,再看一下序列化后的结果

1
{"animal":{"type":"dog","name":"lacy","barkVolume":0.0}}

我们发现为我们多加了一个type属性。

下面试一下反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    @Test
public void whenDeserializingPolymorphic_thenCorrect()
throws IOException {
String json = "{\"animal\":{\"name\":\"lacy\",\"type\":\"cat\"}}";
// {"animal":{"name":"lacy","type":"cat","likesCream":false,"lives":2}}

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

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

}
// 可以正常执行通过。

如果将 String json = "{\"animal\":{\"name\":\"lacy\",\"type\":\"cat\"}}";改为String json = "{\"animal\":{\"name\":\"lacy\",\"type\":\"dog\"}}";就会报错。

6 Jackson其他注解

6.1 @JsonProperty

我们可以添加@JsonProperty注解在JSON中指示属性名称。可以看做是@JsonGetter和@JsonSetter的组合版

在处理非标准的getter和setter时,我们可以使用@JsonProperty来序列化/反序列化属性名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}
}

6.2 @JsonFormat

@JsonFormat注解指定序列化时间类型的格式。

1
2
3
4
5
6
7
8
public class EventWithFormat {
public String name;

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

经测试,@JsonFormat对java8新增的时间类型LocalDateTime等,不适用。

6.3 @JsonUnwrapped

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class UnwrappedUser {
public int id;

@JsonUnwrapped
public Name name;

public UnwrappedUser() {}

public UnwrappedUser(final int id, final Name name) {
this.id = id;
this.name = name;
}

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

public Name() {

}

public Name(final String firstName, final String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
}

序列化测试:

1
2
3
4
5
6
7
8
9
10
11
    @Test
public void whenSerializingUsingJsonUnwrapped_thenCorrect()
throws JsonProcessingException {
UnwrappedUser.Name name = new UnwrappedUser.Name("John", "Doe");
UnwrappedUser user = new UnwrappedUser(1, name);

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

System.out.println(result);
}
// {"id":1,"firstName":"John","lastName":"Doe"}

反序列化测试:

1
2
3
4
5
6
7
8
9
10
11
12
    @Test
public void whenDeserializingUsingJsonUnwrapped_thenCorrect()
throws JsonProcessingException {
String json = "{\"id\":1,\"firstName\":\"John\",\"lastName\":\"Doe\"}";
String json1 = "{\"id\":1,\"name\":{\"firstName\":\"John\",\"lastName\":\"Doe\"}}";

UnwrappedUser bean = new ObjectMapper()
.readerFor(UnwrappedUser.class)
.readValue(json1);
assertEquals("John",bean.name.firstName);
}
// 经测试,json1形式的反序列化后,name属性是没有值的,所以使用@JsonUnwrapped注解后,反序列化时需要注意

6.4 @JsonView

@JsonView表示包含用于序列化/反序列化的属性的视图。也就是我们可以通过@JsonView的方式指定需要序列化那些属性。

1
2
3
4
5
// 定义一个视图类
public class Views {
public static class Public {}
public static class Internal extends Public {}
}

1
2
3
4
5
6
7
8
9
10
public class Item {
@JsonView(Views.Public.class)
public int id;

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

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

测试如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    @Test
public void whenSerializingUsingJsonView_thenCorrect()
throws JsonProcessingException {
Item item = new Item(2, "book", "John");

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

System.out.println(result);

String result2 = new ObjectMapper()
.writerWithView(Views.Internal.class)
.writeValueAsString(item);
System.out.println(result2);
}
/*
{"id":2,"itemName":"book"}
{"id":2,"itemName":"book","ownerName":"John"}
*/

6.5 @JsonManagedReference, @JsonBackReference

@JsonManagedReference和@JsonBackReference可以解决嵌套关系和循环问题

首先先看这么两个类

1
2
3
4
5
6
7
8
9
10
11
public class ItemWithRef {
public int id;
public String itemName;
public UserWithRef owner;
}

public class UserWithRef {
public int id;
public String name;
public List<ItemWithRef> userItems;
}

这两个类中的属性都有各自的属性。假设我们不做约束,看看序列化会有什么结果

1
2
3
4
5
6
7
8
9
10
11
12
    @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);

System.out.println(result);
}
// 此时会报错会报一个很长很长的错误。这里就不贴出来了。

我们为两个类加上上面两个注解再试一次,看看会怎么样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ItemWithRef {
public int id;
public String itemName;

@JsonManagedReference
public UserWithRef owner;
}

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

@JsonBackReference
public List<ItemWithRef> userItems;
}

这次就可以正常序列化了{"id":2,"itemName":"book","owner":{"id":1,"name":"John"}}

注意:直接序列化那个对象的属性上标注@JsonManagedReference

6.6 @JsonIdentityInfo

@JsonIdentityInfo表明在序列化/反序列化时应该使用对象标识——例如,处理无限递归类型的问题。

看下面类似6.5的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class ItemWithIdentity {
public int id;
public String itemName;
public UserWithIdentity owner;
}
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class UserWithIdentity {
public int id;
public String name;
public List<ItemWithIdentity> userItems;
}

测试如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    @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);

System.out.println(result);
}
// {"id":2,"itemName":"book","owner":{"id":1,"name":"John","userItems":[2]}}
/*
{
"id": 2,
"itemName": "book",
"owner": {
"id": 1,
"name": "John",
"userItems": [
2
]
}
}
*/

注意:这里的结果和6.5中的不一样哦

  • 6.5中owner属性中少了userItems属性
  • 这里owner属性中的userItems中使用id来标识。

6.7 @JsonFilter

@JsonFilter注解指定在序列化期间使用的过滤器。

看一个例子:

1
2
3
4
5
@JsonFilter("myFilter")
public class BeanWithFilter {
public int id;
public String name;
}

序列化时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    @Test
public void whenSerializingUsingJsonFilter_thenCorrect()
throws JsonProcessingException {
BeanWithFilter bean = new BeanWithFilter(1, "My bean");

// 这里添加了一个名为`myFilter`的过滤器,作用是:除了`name`属性,其他的都排除在外
FilterProvider filters
= new SimpleFilterProvider().addFilter(
"myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name"));

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

System.out.println(result);
}
// {"name":"My bean"}

7 自定义Jackson注解

接下来,让我们看看如何创建自定义Jackson注解。这里我们需要使用@JacksonAnnotationsInside注解:

1
2
3
4
5
6
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({ "name", "id", "dateCreated" })
public @interface CustomAnnotation {}
// 说是自定义,其实就是使用Jackson原有的注解,将其进行组合,这个注解的作用:忽略空值属性,并按照"name", "id", "dateCreated"排序。

使用

1
2
3
4
5
6
@CustomAnnotation
public class BeanWithCustomAnnotation {
public int id;
public String name;
public Date dateCreated;
}

测试下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void whenSerializingUsingCustomAnnotation_thenCorrect()
throws JsonProcessingException {
BeanWithCustomAnnotation bean
= new BeanWithCustomAnnotation(1, "My bean", null);

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

System.out.println(result);
}
/*
{
"name":"My bean",
"id":1
}
*/

8 Jackson MixIn 注解

看下面的例子

1
2
3
4
5
6
7
public class Item2 {
public int id;
public String itemName;
public User owner;
}
@JsonIgnoreType
public class MyMixInForIgnoreType {}

序列化时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    @Test
public void whenSerializingUsingMixInAnnotation_thenCorrect()
throws JsonProcessingException {
User u = new User(2,"John");

Item2 item = new Item2(1, "book", u);

String result = new ObjectMapper().writeValueAsString(item);
System.out.println(result);

ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(User.class, MyMixInForIgnoreType.class); // 将User列为忽略的类型

String result2 = mapper.writeValueAsString(item);
System.out.println(result2);
}
/*
{"id":1,"itemName":"book","owner":{"id":2,"name":"John"}}
{"id":1,"itemName":"book"}
*/

9. 禁用Jackson注解

1
2
3
    ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.USE_ANNOTATIONS);
// 这样就禁用了注解

看一个例子

1
2
3
4
5
6
7
8
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
public int id;
public String name;
}

MyBean bean = new MyBean(1, null);

如果不禁用注解序列化为:

1
{"id":1}

禁用注解后的结果为:

1
2
3
4
{
"id":1,
"name":null
}

Xiuming Lee wechat
欢迎您扫一扫上面的微信公众号订阅,更多惊喜等着您哦!
-------------本文结束感谢您的阅读-------------