Jackson 注解浅析

607 阅读3分钟

1. Jackson 序列化注解

1.1 @JsonAnyGetter

JsonAnyGetter 标记方法可以将返回的对象展开。这个注解标记的返回值必须是java.util.Map


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

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

    @Test
    public void s1() throws JsonProcessingException {
        ExtendableBean bean = new ExtendableBean("lupeng", new HashMap<>());
        bean.properties.put("attr1", "val1");
        bean.properties.put("attr2", "val2");

        String json = new ObjectMapper().writeValueAsString(bean);
        System.out.println(json);
        // {"name":"lupeng","attr2":"val2","attr1":"val1"}
    }

1.2 @JsonGetter

JsonGetter 将标记的getter方法序列化为json的属性


@AllArgsConstructor
public static class MyBean {
    private int id;
    private String name;

    @JsonGetter(value = "name")
    public String getTheName1() {
        return name;
    }
    // other getter setter
}

    @Test
    public void s2() throws JsonProcessingException {
        MyBean bean = new MyBean(111, "aaa");
        String result = new ObjectMapper().writeValueAsString(bean);
        System.out.println(result);
        //{"id":111,"name":"aaa"}
    }

1.3 @JsonPropertyOrder

@JsonPropertyOrder 指定属相的序列化顺序

@JsonPropertyOrder(alphabetic=true) 属性的序列化方式为字母顺序


@AllArgsConstructor
@JsonPropertyOrder(value = {"name", "id"})
// {"name":"aaa","id":111}
public static class MyBean {
    private int id;
    private String name;

    @JsonGetter(value = "name")
    public String getTheName1() {
        return name;
    }
}

1.4 @JsonRawValue

@JsonRawValue 标记的属性不做转移处理

@Data
@AllArgsConstructor
public static class MyBean1 {
    private int id;
    @JsonRawValue
    private String value;
}

@Test
public void s3() throws JsonProcessingException {
    MyBean1 bean1 = new MyBean1(1, "{"attr":false}");
    String result = new ObjectMapper().writeValueAsString(bean1);
    System.out.println(result);
    // {"id":1,"value":{"attr":false}}
}

1.5 @JsonValue

@JsonValue 作用于整个实例,注释getName以便任何此类实体都通过其名称进行序列化 一个类只能由一个此注解,多个会报错

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

    private Integer id;
    private String name;

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

    //@JsonValue
    //public Integer getId() {
    //    return id;
    //}
}

@Test
public void s4() throws JsonProcessingException {
    TypeEnumWithValue type1 = TypeEnumWithValue.TYPE1;
    System.out.println(new ObjectMapper().writeValueAsString(type1));
    // "Type A"
}

1.6 @JsonRootName

@JsonRootName 作用于整个对象,注释的对象自动设置根属相, 要使用这个功能需要开启

objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);

@Data
@AllArgsConstructor
@JsonRootName(value = "user")
public static class MyBean2 {
    private int id;
    private String name;
}

@Test
public void s5() throws JsonProcessingException {
    MyBean2 bean2 = new MyBean2(1, "222");
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
    System.out.println(objectMapper.writeValueAsString(bean2));
    // {"user":{"id":1,"name":"222"}}
}

1.7 @JsonSerialize(using = **.class)

@JsonSerialize 指定序列化这个属性的序列化器,支持自定义序列化器

@Data
@AllArgsConstructor
public static class MyBean3 {
    private int id;
    private String name;
    @JsonSerialize(using = CustomSerialize.class)
    private SuperBean superBean;
}

public static class SuperBean {}

public static class CustomSerialize
        extends StdSerializer<SuperBean> {

    public CustomSerialize() {
        this(null);
    }

    public CustomSerialize(Class<SuperBean> t) {
        super(t);
    }

    @Override
    public void serialize(SuperBean superBean, JsonGenerator jsonGenerator,
            SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeString("Im super bean");
    }
}

@Test
public void s6() throws JsonProcessingException {
    MyBean3 bean3 = new MyBean3(1, "33", new SuperBean());
    ObjectMapper objectMapper = new ObjectMapper();
    System.out.println(objectMapper.writeValueAsString(bean3));
    // {"id":1,"name":"33","superBean":"Im super bean"}
}

2. Jackson 反序列化注解

2.1 @JsonCreator

@JsonCreator 标记反序列的构造函数或者工厂

@Data
public static class Bean1 {
    public int id;
    public String name;

    @JsonCreator
    public Bean1(
            @JsonProperty("id") int id,
            // 这个类中没有这个属性
            @JsonProperty("theName") String name) {
        this.id = id;
        this.name = name;
    }
}

@Test
public void s1() throws JsonProcessingException {
    String json = """
            {
                "id":1,
                "theName":"My bean"
            }
            """.strip();
    Bean1 bean1 = objectMapper.readValue(json, Bean1.class);
    System.out.println(bean1);
}

2.2 @JsonAnySetter

@JsonAnySetter 在反序列化的时候将没有映射到的属性放到Map中

@Data
public static class Bean2 {
    public int id;
    public String theName;

    private Map<String, Object> properties = new HashMap<>();

    // 将没有匹配到的字段放到Map中
    @JsonAnySetter
    public void add(String k, Object v) {
        properties.put(k, v);
    }
}

@Test
public void s2() throws JsonProcessingException {
    String json = """
            {
                "id":1,
                "theName":"My bean",
                "attr1":"val1",
                "attr2": {
                    "k1":"v1"
                }
            }
            """.strip();
    Bean2 bean2 = objectMapper.readValue(json, Bean2.class);
    System.out.println(bean2);
}

2.3 @JsonSetter

@JsonSetter 当我们需要读取一些 JSON 数据但目标实体类与该数据不完全匹配时,这个注解可以将不匹配的字段解析。

2.4 @JsonDeserialize

@JsonDeserialize 使用自定义的反序列化器

@Data
public static class Bean3 {
    public int id;
    @JsonDeserialize(using = CustomDeserialize.class)
    public String theName;
}

public static class CustomDeserialize extends StdDeserializer<String> {
    public CustomDeserialize() {
        this(null);
    }

    public CustomDeserialize(Class<String> t) {
        super(t);
    }

    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
        String text = p.getText();
        return "CustomDeserialize: " + text;
    }
}

@Test
public void s3() throws JsonProcessingException {
    String json = """
            {
                "id":1,
                "theName":"My bean"
            }
            """.strip();
    Bean3 bean3 = objectMapper.readValue(json, Bean3.class);
    System.out.println(bean3);
}

3.5 @JsonAlias

@JsonAlias 别名,反序列化的时候可以将指定的别名匹配到的属性序列化

public static class Bean4 {
    public int id;
    public String firstName;
    @JsonAlias(value = {"fName", "first_name"})
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
}

@Test
public void s4() throws JsonProcessingException {
    String json = """
            {
                "id":1,
                "first_name":"My bean"
            }
            """.strip();
    Bean4 bean4 = objectMapper.readValue(json, Bean4.class);
    System.out.println(bean4);
}

3. Jackson 属性相关的注解

3.1 @JsonIgnoreProperties、@JsonIgnore、@JsonIgnoreType

在序列化和方序列化时设置忽略的属性

@JsonIgnoreProperties 注释在类上指定多个忽略的属性

@JsonIgnore 注释在属性上

@JsonIgnoreType 带有此注解的类型忽略

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

3.2 @JsonInclude

@JsonInclude 可以设置排除 null/空/默认值的属性

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

@Test
public void s5() throws JsonProcessingException {
    Bean5 bean5 = new Bean5(1, null);
    System.out.println(objectMapper.writeValueAsString(bean5));
    // {"id":1,"name":null} 不开启
    // {"id":1} 开启之后
}

3.3 @JsonAutoDetect

@JsonAutoDetect 属性访问级别,设置哪些访问级别可以被序列化

@AllArgsConstructor
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
//@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.DEFAULT)
public class PrivateBean {
    private int id;
    private String name;
}
@Test
public void s6() throws JsonProcessingException {
    PrivateBean bean = new PrivateBean(1, "aaa");
    System.out.println(objectMapper.writeValueAsString(bean));
    // JsonAutoDetect.Visibility.DEFAULT {}
    // JsonAutoDetect.Visibility.ANY {"id":1,"name":"aaa"}
}

3.4 @JsonProperty

@JsonProperty 用来标记序列化和反序列化时属性的名字

3.5 @JsonFormat

@JsonFormat 处理时间的格式化

@Data
@AllArgsConstructor
public class EventWithFormat {
    public String name;

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

@Test
public void s8() throws JsonProcessingException {
    EventWithFormat event = new EventWithFormat("aa", new Date());
    System.out.println(objectMapper.writeValueAsString(event));
    // {"name":"aa","eventDate":"2022-04-10 12:34:26"} 时间和当前时间对不上
    // 添加 timezone = "GMT+8" 之后时间正确
}

3.6 @JsonUnwrapped

@JsonUnwrapped 标记的属性在序列化时展开

@Data
@AllArgsConstructor
public class UnwrappedUser {
    public int id;

    @JsonUnwrapped
    public Name name;

    @Data
    @AllArgsConstructor
    public static class Name {
        public String firstName;
        public String lastName;
    }
}

@Test
public void s9() throws JsonProcessingException {
    // serialize
    UnwrappedUser user = new UnwrappedUser(1, new UnwrappedUser.Name("zhang", "san"));
    System.out.println(objectMapper.writeValueAsString(user));
    //{"id":1,"firstName":"zhang","lastName":"san"}
}

4. Jackson 多态

一段json文本,可以根据一个字段来区分序列化成哪个具体的实现类,

下面一个例子。动物园包含动物,根据type 字段来确定是哪种动物。

@Data
public static class Zoo {
    private Animal animal;
}

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

    public abstract void call();
}

@Data
@JsonTypeName("cat")
public static class Cat extends Animal {
    @Override
    public void call() {
        System.out.println("喵喵喵");
    }
}

@Data
@JsonTypeName("dog")
public static class Dog extends Animal {

    @Override
    public void call() {
        System.out.println("汪汪汪");
    }
}

@Test
public void s7() throws JsonProcessingException {
    String json = """
            {
                "animal": {
                    "name": "花花",
                    "type": "cat"
                }
            }
            """.strip();
    Zoo zoo = objectMapper.readValue(json, Zoo.class);
    zoo.animal.call();
}

5. Jackson 读写json

5.1 反序列化json数组

使用 new TypeReference<List>() {} 标记

@NoArgsConstructor
@AllArgsConstructor
public static class Bean1 {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

/**
 * 将对象序列化为json
 */
@Test
public void s1() throws JsonProcessingException {
    String json = """
            [{"id":11, "name":"peng"},{"id":111, "name":"guo"}]
            """.strip();
    List<Bean1> list = objectMapper.readValue(json, new TypeReference<List<Bean1>>() {});
    System.out.println(list);
}

5.2 反序列化json为java.util.Map

也是使用new TypeReference<Map<String, Object>>() {}

public class Test {
    @Test
    public void s2() throws JsonProcessingException {
        String json = """
                {"id":111, "name":"guo"}
                """.strip();
        Map<String, Object> map = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {
        });
        System.out.println(map);
    }
}