alamide的笔记库「 87篇笔记 」「 小破站已建 0 天啦 🐶 」


Jackson

2023-05-03, by alamide

文档在这里

1.引入 Jackson

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.13.3</version>
</dependency>

2.Jackson Serialization Annotations

2.1 @JsonAnyGetter

可以将 key/value 型的拆解

public class ExtendableBean {
    public String name;
    private Map<String, String> properties = new HashMap<>();

    public ExtendableBean(String name) {
        this.name = name;
    }

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

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

@Test
public void testJsonAnyGetter() throws IOException {

    ExtendableBean bean = new ExtendableBean("My bean");
    bean.add("attr1", "val1");
    bean.add("attr2", "val2");

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

使用 @JsonAnyGetter 输出:

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

不使用 @JsonAnyGetter 或 @JsonAnyGetter(enabled = false) 输出:

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

2.2 @JsonGetter

@AllArgsConstructor
public class MyBean {
    public int id;

    private String name;

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

@Test
public void testJsonGet() throws JsonProcessingException {
    MyBean myBean = new MyBean(1, "alamide");
    final String string = new ObjectMapper().writeValueAsString(myBean);
    //1.使用 JsonGetter 输出 {"id":1,"name":"alamide"}
    //2.不使用 JsonGetter 输出 {"id":1,"theName":"alamide"}
    System.out.println(string);
}

2.3 @JsonPropertyOrder

设置序列化时 key 的顺序

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

    public String name;
}

@Test
public void testJsonPropertyOrder() throws JsonProcessingException {
    MyBean myBean = new MyBean(1, "alamide");
    final String string = new ObjectMapper().writeValueAsString(myBean);
    System.out.println(string);
}

输出:

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

2.4 @JsonRawValue

Json 格式的数据以什么形式输出

@AllArgsConstructor
public class RawBean {
    public String name;

    @JsonRawValue
    public String json;
}

@Test
public void testJsonRawValue() throws JsonProcessingException {
    RawBean rawBean = new RawBean("My Bean", "{\"attr\":false}");
    final String string = new ObjectMapper().writeValueAsString(rawBean);
    //1.使用 @JsonRawValue {"name":"My Bean","json":{"attr":false}}
    //2.不使用 @JsonRawValue {"name":"My Bean","json":"{\"attr\":false}"}
    System.out.println(string);
}

2.5 @JsonValue

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

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

    private Integer id;
    private String name;

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

@Test
public void whenSerializingUsingJsonValue_thenCorrect()
        throws JsonParseException, IOException {

    String enumAsString = new ObjectMapper()
            .writeValueAsString(TypeEnumWithValue.TYPE1);
    //1.使用 @JsonValue 输出:"Type A"
    //2.不使用则输出 "TYPE1"
    //3.一个 POJO 只有一个方法可使用 @JsonValue,
    System.out.println(enumAsString);
}

2.6 @JsonRootName

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

@Test
public void testJsonRootName() throws JsonProcessingException {
    UserWithRoot userWithRoot = new UserWithRoot(1, "alamide");
    final ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
    final String string =objectMapper.writeValueAsString(userWithRoot);
    //输出:{"user":{"id":1,"name":"alamide"}}
    System.out.println(string);
}

2.7 @JsonSerialize

定义序列化的格式

@AllArgsConstructor
public class EventWithSerializer {

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

public class CustomDateSerializer extends StdSerializer<Date> {

    private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    protected CustomDateSerializer(Class<Date> t) {
        super(t);
    }

    public CustomDateSerializer(){
        this(null);
    }

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

@Test
public void testJsonSerialize() throws JsonProcessingException {
    EventWithSerializer eventWithSerializer = new EventWithSerializer("alamide", new Date());
    final String json = new ObjectMapper().writeValueAsString(eventWithSerializer);
    //{"name":"alamide","eventDate":"2023-05-03 22:35"}
    System.out.println(json);
}

3.Jackson Deserialization Annotations

3.1 @JsonCreator

当key 不匹配时使用,使用时,构造器参数都需要加上 @JsonProperty

@ToString
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 testJsonCreator() throws JsonProcessingException {
    String json = "{\"id\":1,\"theName\":\"My bean\"}";
    final BeanWithCreator bean = new ObjectMapper().readerFor(BeanWithCreator.class).readValue(json);
    //BeanWithCreator(id=1, name=My bean)
    System.out.println(bean);
}

3.2 @JacksonInject

属性从 Inject 获取,而不是从 Json 字符串

@ToString
public class BeanWithInject {
    @JacksonInject
    public int id;

    public String name;
}

@Test
public void testJsonInject() throws JsonProcessingException {
    String json = "{\"name\":\"My bean\"}";
    InjectableValues inject = new InjectableValues.Std().addValue(int.class, 100);
    final BeanWithInject bean = new ObjectMapper()
            .reader(inject)
            .forType(BeanWithInject.class)
            .readValue(json);
    //BeanWithInject(id=100, name=My bean)
    System.out.println(bean);
}

3.3 @JsonAnySetter

可以将多余的属性,放置入 key/value 中

@ToString
@NoArgsConstructor
public class ExtendableBean {
    public String name;
    private Map<String, String> properties = new HashMap<>();

    public ExtendableBean(String name) {
        this.name = name;
    }


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

@Test
public void testJsonAnySetter() throws JsonProcessingException {
    String json
            = "{\"name\":\"My bean\",\"attr2\":\"val2\",\"attr1\":\"val1\"}";
    final ExtendableBean extendableBean = new ObjectMapper().readerFor(ExtendableBean.class).readValue(json);
    //ExtendableBean(name=My bean, properties={attr2=val2, attr1=val1})
    System.out.println(extendableBean);
}

3.4 @JsonSetter

指定 key

@AllArgsConstructor
@NoArgsConstructor
@JsonPropertyOrder({"name", "id"})
@ToString
public class MyBean {
    public int id;

    private String name;

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

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

    MyBean bean = new ObjectMapper()
            .readerFor(MyBean.class)
            .readValue(json);
    //MyBean(id=1, name=My bean)
    System.out.println(bean);
}

3.5 @JsonDeserialize

定制反序列化器

@AllArgsConstructor
@ToString
@NoArgsConstructor
public class EventWithSerializer {

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

@Test
public void testDeserializer() throws JsonProcessingException {
    String json
            = "{\"name\":\"party\",\"eventDate\":\"20-12-2014 02:30:00\"}";
    final EventWithSerializer event = new ObjectMapper().readerFor(EventWithSerializer.class).readValue(json);
    //EventWithSerializer(name=party, eventDate=Thu Jun 06 02:30:00 CST 26)
    System.out.println(event);
}

3.6 @JsonAlias

指定多个可选名

@Data
@ToString
public class AliasBean {
    @JsonAlias({"1Name", "first_name"})
    private String firstName;

    private String lastName;
}

@Test
public void testJsonAlias() throws JsonProcessingException {
    String json = "{\"1Name\": \"John\", \"lastName\": \"Green\"}";
    AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json);
    System.out.println(aliasBean);
}

4.Jackson Property Inclusion Annotations

4.1 @JsonIgnoreProperties

忽略属性

@Data
@AllArgsConstructor
@JsonIgnoreProperties({"name"})
@NoArgsConstructor
public class BeanWithIgnore {
    public int id;
    private String name;
}

@Test
public void testJsonIgnore() throws JsonProcessingException {
    BeanWithIgnore beanWithIgnore=new BeanWithIgnore(1, "alamide");
    final String string = new ObjectMapper().writeValueAsString(beanWithIgnore);
    //{"id":1}
    System.out.println(string);
}

4.2 @JsonIgnore

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BeanWithIgnore {
    public int id;
    @JsonIgnore
    private String name;
}

@Test
public void testJsonIgnore() throws JsonProcessingException {
    BeanWithIgnore beanWithIgnore=new BeanWithIgnore(1, "alamide");
    final String string = new ObjectMapper().writeValueAsString(beanWithIgnore);
    //{"id":1}
    System.out.println(string);
}

4.3 @JsonIgnoreType

@AllArgsConstructor
public class User {
    public int id;

    public Name name;

    @JsonIgnoreType
    public static class Name {
        public String firstName;

        public String lastName;
    }
}

@Test
public void testJsonIgnoreType() throws JsonProcessingException {
    User.Name name = new User.Name();
    name.firstName = "ala";
    name.lastName = "mide";
    User user = new User(1, name);
    final String string = new ObjectMapper().writeValueAsString(user);
    //{"id":1}
    System.out.println(string);
}

4.4 @JsonInclude

@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MyBean {
    public int id;

    public String name;
}

@Test
public void testJsonInclude() throws JsonProcessingException {
    MyBean myBean = new MyBean(1, null);
    final String string = new ObjectMapper().writeValueAsString(myBean);
    //{"id":1},如果不加JsonInclude,则输出 {"id":1,"name":null}
    System.out.println(string);
}

4.5 @JsonIncludeProperties

@JsonIncludeProperties({"name"})
@AllArgsConstructor
public class BeanWithInclude {
    public int id;

    public String name;
}

@Test
public void testJsonIncludeProperties() throws JsonProcessingException {
    BeanWithInclude bean = new BeanWithInclude(1, "alamide");
    final String string = new ObjectMapper().writeValueAsString(bean);
    System.out.println(string);
}

4.6 @JsonAutoDetect

指定哪些属性是可见的、哪些不可见

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

@Test
public void testJsonAutoDetect() throws JsonProcessingException {
    PrivateBean privateBean = new PrivateBean(1, "alamide");
    final String string = new ObjectMapper().writeValueAsString(privateBean);
    //{}
    System.out.println(string);
}

5.Jackson Polymorphic Type Handling Annotations

@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Zoo {
    public Animal animal;
    @AllArgsConstructor
    @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;
    }
    @JsonTypeName("dog")
    public static class Dog extends Animal {
        public double barkVolume;
        public Dog(){
            super(null);
        }
        public Dog(String name, double barkVolume) {
            super(name);
            this.barkVolume = barkVolume;
        }
    }

    @JsonTypeName("cat")
    public static class Cat extends Animal {
        boolean likesCream;
        public int lives;
        public Cat(){
            super(null);
        }
        public Cat(String name, boolean likesCream, int lives) {
            super(name);
            this.likesCream = likesCream;
            this.lives = lives;
        }
    }
}

@Test
public void testType() throws JsonProcessingException {
    Zoo zoo = new Zoo(new Zoo.Dog("dog", 120));
    final String string = new ObjectMapper().writeValueAsString(zoo);
    //{"animal":{"type":"dog","name":"dog","barkVolume":120.0}}
    System.out.println(string);

    String json = "{\"animal\":{\"name\":\"lacy\",\"type\":\"cat\"}}";
    final Zoo value = new ObjectMapper().readerFor(Zoo.class).readValue(json);
    //class com.alamide.third.entities.Zoo$Cat
    System.out.println(value.animal.getClass());
}

6.Jackson General Annotations

6.1 @JsonProperty

指定在 Json 中的 key,可以代替 JsonSetter、JsonGetter

@AllArgsConstructor
@NoArgsConstructor
@ToString
public class MyBean {
    public int id;
    private String name;
    
    @JsonProperty("diyName")
    public String getTheName() {
        return name;
    }

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

@Test
public void testJsonProperty() throws JsonProcessingException {
    MyBean myBean = new MyBean(1, "alamide");
    final String string = new ObjectMapper().writeValueAsString(myBean);
    //{"id":1,"diyName":"alamide"}
    System.out.println(string);
}

6.2 @JsonFormat

可以替换 @JsonSerialize、@JsonDeserialize

@AllArgsConstructor
@ToString
@NoArgsConstructor
public class EventWithSerializer {

    public String name;
//    @JsonSerialize(using = CustomDateSerializer.class)
//    @JsonDeserialize(using = CustomDateDeserializer.class)
    @JsonFormat(
            shape = JsonFormat.Shape.STRING,
            pattern = "yyyy-MM-dd HH:mm"
    )
    public Date eventDate;
}

@Test
public void testJsonSerialize() throws JsonProcessingException {
    EventWithSerializer eventWithSerializer = new EventWithSerializer("alamide", new Date());
    final String json = new ObjectMapper().writeValueAsString(eventWithSerializer);
    //{"name":"alamide","eventDate":"2023-05-06 08:29"}
    System.out.println(json);
}

6.3 @JsonUnwrapped

unwrapped/flattened when serialized/deserialized

@AllArgsConstructor
public class User {
    public int id;

    @JsonUnwrapped
    public Name name;

    public static class Name {
        public String firstName;

        public String lastName;
    }
}

@Test
public void testJsonIgnoreType() throws JsonProcessingException {
    User.Name name = new User.Name();
    name.firstName = "ala";
    name.lastName = "mide";
    User user = new User(1, name);
    final String string = new ObjectMapper().writeValueAsString(user);
    //不加 @JsonUnwrapped {"id":1,"name":{"firstName":"ala","lastName":"mide"}}
    //加 @JsonUnwrapped {"id":1,"firstName":"ala","lastName":"mide"}
    System.out.println(string);
}

6.4 @JsonView

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

可以指定哪些试图显示属性

 public class Views {
    public static class Public {}
    public static class Internal extends Public {}
}
@AllArgsConstructor
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 testJsonView() throws JsonProcessingException {
    Item item = new Item(2, "book", "John");

    String result = new ObjectMapper()
            .writerWithView(Views.Public.class)
            .writeValueAsString(item);
    //{"id":2,"itemName":"book"}
    System.out.println(result);
}

6.5 @JsonManagedReference, @JsonBackReference

避免循环引用

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

    @JsonManagedReference
    public UserWithRef owner;
}

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

    @JsonBackReference
    public List<ItemWithRef> userItems = new ArrayList<>();

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

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

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

6.6 @JsonIdentityInfo

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

同样是解决循环引用的问题

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

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

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

@Test
public void testLoop() throws JsonProcessingException {
    UserWithIdentity user = new UserWithIdentity(1, "John");
    ItemWithIdentity item = new ItemWithIdentity(2, "book", user);
    user.userItems.add(item);
    String result = new ObjectMapper().writeValueAsString(item);
    //{"id":2,"itemName":"book","owner":{"id":1,"name":"John","userItems":[2]}}
    System.out.println(result);
}

6.7 @JsonFilter

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

@Test
public void testJsonFilter() 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);
    //{"name":"My bean"}
    System.out.println(result);
}

7.Custom Jackson Annotation

组合使用 Jackson Annotation

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

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


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

    String result = new ObjectMapper().writeValueAsString(bean);
    //{"name":"My bean","id":1}
    System.out.println(result);
}

8.Jackson MixIn Annotations

@JsonIgnoreType
public class MyMixInForIgnoreType {}

@AllArgsConstructor
public class Item {
    public int id;

    public String itemName;

    public User user;
}

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

    String result = new ObjectMapper().writeValueAsString(item);
    //{"id":1,"itemName":"book","user":null}
    System.out.println(result);

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

    result = mapper.writeValueAsString(item);
    //{"id":1,"itemName":"book"}
    System.out.println(result);
}

9.Disable Jackson Annotation

使所有的 Jackson 失效

@AllArgsConstructor
@NoArgsConstructor
@ToString
public class MyBean {
    public int id;
    private String name;
    @JsonProperty("diyName")
    public String getTheName() {
        return name;
    }

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

@Test
public void testJsonGet() throws JsonProcessingException {
    MyBean myBean = new MyBean(1, "alamide");
    ObjectMapper mapper = new ObjectMapper();
    mapper.disable(MapperFeature.USE_ANNOTATIONS);
    final String string = mapper.writeValueAsString(myBean);
    //{"id":1,"theName":"alamide"}
    System.out.println(string);
}
Tags: java - json
~ belongs to alamide@163.com