美文网首页
1. Jackson 注解使用指南

1. Jackson 注解使用指南

作者: 钟志弘 | 来源:发表于2020-02-22 19:38 被阅读0次

    introduction

    Jackson, formerly known as hte standard JSON library for Java, or, as the "best JSON parser for Java", or simply as "JSON for Java.", more than that Jackson is a suite of data-processing tools for Java, including the flagship streaming[JOSON], etc...

    以下内容翻译自baeldung

    概括

    这篇文章将带你深入Jackson Annotations并学习如何使用这些Annotations、 如何创建自定义的注解, 并且如何禁用它们。

    Jaskson Serialization Annotations( Jackson 序列化注解 )

    @JsonAnyGetter

    这个注解允许使用Map灵活输出属性,下面是代码片段——ExtendableBean 类有一个 name 属性 和一个可拓展的 key/value 格式的属性。

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

    当我们序列化这个实体的实例的时候,我们将得到所有Map中 key-values ,并以标准的形式输出:
    {
    "name":"My bean",
    "attr2":"val2",
    "attr1":"val1"
    }

    实践代码:

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

    同样的, 我们可以使用可选参数 enabled ,传入false 禁用 @JsonAnyGetter, 本例中,序列化后的 Map 将会转化为Json格式的 properties 变量。

    @JsonGetter

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

    下面这个实例中,我们指定名为getTheName() 方法作为 Mybean 实体中 name 属性的 getter 方法。

    public class MyBean {
        public int id;
        private String name;
    
        @JsonGetter("name")
        public String getTheName() {
            return name;
        }
    }
    

    实践代码:

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

    @JsonPropertyOrder

    用以指定Json序列化顺序, 自定义属性顺序代码:

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

    @JsonRawValue

    用以命令 Jackson 原原本本地序列化一个属性。

    public class RawBean {
        public String name;
    
        @JsonRawValue
        public String json;
    }
    

    以上代码将会输出以下格式
    {
    "name":"My bean",
    "json":{
    "attr":false
    }
    }

    @JsonValue

    @JsonValue 标识地方法会被Jackson库用于序列化整个对象实例,

        TYPE1(1, "Type A"), TYPE2(2, "Type 2");
    
        private Integer id;
        private String name;
    
        // standard constructors
    
        @JsonValue
        public String getName() {
            return name;
        }
    }
    

    例如,在枚举类型中,我们使用 @JsonValue 注解 getName 方法, 整个实体将会被序列化为它的 name 属性

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

    @JsonRootName

    当启用Wrapping的时候, @JsonRootName 注解用于指定根 Wrapper 的名字。
    Wrapping 指的是, 例如一个 User 实例原本序列化为以下格式:
    {
    "id": 1,
    "name": "John"
    }
    启用被 Wrapped 后将变成以下格式:
    {
    "User": {
    "id": 1,
    "name": "John"
    }
    }

    案例: 使用 @JsonRootName 指定一个隐式的Wrapper 实体的名字 :

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

    一般情况下, Wrapper的名字是类的名字 - UserWithRoot, 使用这个注解后,我们会得到更简洁的类名字。

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

    输出:

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

    tip: Jackson 2.4以后, 一个新的可选参数namespace可用, 该选项用于像是XML的数据格式。 如果我们加上这个参数,那么其指定的值将成为一个完全合法的名字。

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

    使用XmlMapper 对其序列化,将会输出以下格式:

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

    @JsonSerialize

    @JsonSerialize 指定一个自定义序列化器, 用于序列化一个实体。
    快速示例——使用@JsonSerialize 指定CustomDateSerilizer 类序列化eventDate属性。

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

    CustomDateSerilizer 序列化器参考实现:

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

    反序列注解

    @JsonCreator

    用于调整用于反序列的构造函数/工厂。
    当我们需要序列化一些并不需要完全匹配目标实体的JSON的时候,可以用 @JsonCreator 注解

    假设我们需要反序列下面这个JSON:
    {
    "id":1,
    "theName":"My bean"
    }

    然而目标实体只有name而并没有theName字段。 在不改变实体的前提下,我们需要对反序列过程更大程度的控制——用@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;
        }
    }
    

    @JacksonInject

    @JacksonInject 标识一个属性将被注入其值,而非从JSON数据。
    对id 属性进行注入:

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

    @JsonAnySetter

    @JsonAnySetter 允许使用 Map 灵活加入属性。 在反序列化过程中, JSON中的属性会轻松地加入到map中。

    使用@JsonAnySetter 反序列化实体类 EntendableBean:

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

    输出:

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

    译者:结合 @JsonAnyGetter 加深印象

    @JsonSetter

    @JsonSetter 作为@JsonProperty地替代——将一个方法标记为setter。
    当我们需要读取JSON数据但是目标实体类并不能完全匹配对应字段的时候, 这个注解将非常有用。
    下面这个示例指定MyBean 实体类中的 setTheName() 作为 name 属性的 setter 。

    public class MyBean {
        public int id;
        private String name;
    
        @JsonSetter("name")
        public void setTheName(String name) {
            this.name = name;
        }
    }
    

    @JsonDeserialize

    @JsonDeserialize 标志一个自定义反向序列器

    示例, 使用@JsonDeserialize 标志 CustomDateDeserializer 作为 eventDate 属性的反向序列器:

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

    自定义反向序列器代码:

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

    @JsonAlias

    @JsonAlias 在反序列过程中为属性定义一个或多个别名

    示例:

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

    在以上的POJO, Jackson库将JSON中带有诸如 fName, f_name, firstName 的字段反序列化到firstName 变量中。

    Jackson Property Inclusion Annotations(Jackson 包含注解)

    @JsonIgnoreProperties

    @JsonIgnoreProperties 是一个类级别的注解, 它标记一个属性或者一个属性列表,被标记的属性或属性列表将会被忽略输出

    示例, 从序列化中忽略id属性

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

    @JsonIgnore

    @JsonIgnore 注解用于标记一个字段级别的属性。
    示例, 在序列化中忽略id属性

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

    @JsonIgnoreType

    @JsonIgnoreType 将忽略所有被注解的属性类型
    示例, 忽略所有类型为Name的属性

    public class User {
        public int id;
        public Name name;
    
        @JsonIgnoreType
        public static class Name {
            public String firstName;
            public String lastName;
        }
    }
    

    @JsonInclude

    使用 @JsonInclude 排除empty/null/default的值
    示例, 序列化中排除所有null 值

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

    @JsonAutoDetect

    使用@JsonAutoDtect覆盖默认语义下的属性可见性。
    示例,启用序列化私有属性

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

    Jackson Polymorphic Type Handling Annotations(Jackson 多态类型处理注解)

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

    测试代码:

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

    输出:

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

    使用以下JSON类型对实体类反序列化:

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

    反序列获得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());
    }
    

    相关文章

      网友评论

          本文标题:1. Jackson 注解使用指南

          本文链接:https://www.haomeiwen.com/subject/zwglqhtx.html