Jackson注解使用示例

原文地址

1 概述

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

2 Jackson序列化注解

2.1 @JsonAnyGetter

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

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中的所有键值作为标准的纯属性获取,如下:

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

测试:

    @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方法:

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

测试:

    @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实体的属性设置自定义顺序:

@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作为实体的值:

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

测试:

    @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,以便任何这样的实体都通过其名称序列化:

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

测试:

    @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串外面再包裹一层。
假设之前我们的序列化之后是这样的:

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

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

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

看一下如何使用:

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

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

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

xml效果是这样的

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

2.7 @JsonSerialize

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

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

public class EventWithSerializer {
    public String name;
 
    @JsonSerialize(using = CustomDateSerializer.class)
    public Date eventDate;
}

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

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

让我们测试下:

    @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如下:

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

但是,我们的目标实体中没有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;
    }
}

测试

    @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数据获取其值。

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

测试如下:

    @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正好相反。

public class ExtendableBean {
    public String name;
    private Map<String, String> properties;
 
    @JsonAnySetter
    public void add(String key, String value) {
        properties.put(key, value);
    }
}

假设我们的json是这样的:

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

那么attr2attr1会注入到Map中。

3.4 @JsonSetter

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

3.5 @JsonDeserialize

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

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

public class EventWithSerializer {
    public String name;

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

自定义的反序列化器:

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

测试:

    @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在反序列化期间为属性定义一个或多个备用名称。

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

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

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

    @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:

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

4.2 @JsonIgnore

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

public class BeanWithIgnore {
    @JsonIgnore
    public int id;
 
    public String name;
}

4.3 @JsonIgnoreType

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

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的属性。

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

4.5 @JsonAutoDetect

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

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

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

测试:

    @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

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

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

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

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

    @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类上加上以上注解,再看一下序列化后的结果

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

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

下面试一下反序列化

    @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来序列化/反序列化属性名:

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注解指定序列化时间类型的格式。

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定义在序列化/反序列化时应该解包/展平的值。

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

序列化测试:

    @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"}

反序列化测试:

    @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的方式指定需要序列化那些属性。

// 定义一个视图类
public class Views {
    public static class Public {}
    public static class Internal extends Public {}
}
public class Item {
    @JsonView(Views.Public.class)
    public int id;

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

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

测试如下:

    @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可以解决嵌套关系和循环问题

首先先看这么两个类

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

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

    @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);
    }
// 此时会报错会报一个很长很长的错误。这里就不贴出来了。

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

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的例子

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

测试如下:

    @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注解指定在序列化期间使用的过滤器。

看一个例子:

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

序列化时:

    @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注解:

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

使用

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

测试下:

@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 注解

看下面的例子

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

序列化时:

    @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注解

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

看一个例子

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

MyBean bean = new MyBean(1, null);

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

{"id":1}

禁用注解后的结果为:

{
    "id":1,
    "name":null
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章