首页 > 解决方案 > 更好地控制 jackson2 反序列化

问题描述

我有这堂课:

class Address {
  int id;
  String address;
  // ... other fields
}

我还有许多其他嵌入的类,Address例如:

class Person {
  int id;
  String name;
  Address address;
  // ... other fields
}

我收到一个代表一个人的 json,例如:

{
  "id": 10,
  "name": "John",
  "addressId": 50,
  // ... other fields
}

我可以将上述反序列化为

class PersonJson {
  int id;
  String name;
  int addressId;
  // ... other fields
}

然后转换PersonJsonPerson.

但是,这可能发生在层次结构的更深处。我有Organization一个List<Person>,所以我需要有OrganizationJsonList<PersonJson>然后我需要转换为Organizationand List<Person>

或者,我可以PersonAddress. 我认为我不能重用其中的大部分内容,并且大多数其他字段默认情况下会被反序列化(即原语等)ObjectMapper

两者都是可行的,但两者都是ObjectMapper已经完成的工作的重复,需要在多个地方进行维护,这很痛苦。有没有办法配置ObjectMapper自定义反序列化字段(包括在集合中,例如List<Address>)或其他方式来避免重复?

标签: javajsonjacksonjackson2

解决方案


我的第一个尝试是将@JsonProperty@JsonCreator注释结合起来,以指示对象映射器解决(没有双关语)反序列化到正确的嵌套对象。

为了简单起见,并通过您的评论了解您的不变性,下面有一个使用 lombok 的示例。

import java.io.IOException;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;

import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NonNull;
import lombok.ToString;

public class JsonTest {

    @Data
    @Builder(toBuilder = true)
    @ToString
    @Getter
    static class Address {
        int id;
        @NonNull
        String address;

        @JsonCreator
        public static Address factory(int id) {
            return new AddressBuilder().id(id).address("getAddressLogicHere").build();
        }
    }

    @Data
    @JsonDeserialize(builder = Person.PersonBuilder.class)
    @Builder(toBuilder = true)
    @ToString
    @Getter
    static class Person {
        private final int id;
        @NonNull
        private final String name;
        @JsonProperty("addressId")
        private final Address address;

        @JsonPOJOBuilder(withPrefix = "")
        public static class PersonBuilder {
        }
    }

    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
        String json = "{\n" + 
                "  \"id\": 10,\n" + 
                "  \"name\": \"John\",\n" + 
                "  \"addressId\": 50\n" + 
                "}";
        Person person = new ObjectMapper().readValue(json, Person.class);
        System.out.println(person);
        //JsonTest.Person(id=10, name=John, address=JsonTest.Address(id=50, address=getAddressLogicHere))
    }

}

推荐阅读