当字段为可选时,jackson不会从json读回数据

时间:2016-08-05 22:27:15

标签: java json java-8 jackson optional

我正在使用Java 8来执行此任务。我还遵循JDK8数据类型的依赖工作。

        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jdk8</artifactId>
            <version>2.6.3</version>
        </dependency>

我有一个类似于

的课程
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Optional;

public class Person {
    private String firstName;
    private String lastName;
    private int age;
    private Optional<Address> address;
    private Optional<String> phone;

    private Person() {
    }

    public Person(String firstName, String lastName, int age) {
        this(firstName, lastName, age, Optional.empty(), Optional.empty());
    }

    public Person(String firstName, String lastName, int age,
                  Optional<Address> address, Optional<String> phone) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.address = address;
        this.phone = phone;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    @JsonIgnore
    public Optional<Address> getAddress() {
        return address;
    }

    @JsonIgnore
    public Optional<String> getPhone() {
        return phone;
    }

    @JsonProperty("address")
    private Address getAddressForJson(){
        return address.orElse(null);
    }

    @JsonProperty("phone")
    private String getPhoneForJson() {
        return phone.orElse(null);
    }
}

public class Address {
    private String street;
    private String city;
    private String state;
    private int zip;
    private String country;

    public Address(String street, String city, String state, int zip, String country) {
        this.street = street;
        this.city = city;
        this.state = state;
        this.zip = zip;
        this.country = country;
    }

    public String getStreet() {
        return street;
    }

    public String getCity() {
        return city;
    }

    public String getState() {
        return state;
    }

    public int getZip() {
        return zip;
    }

    public String getCountry() {
        return country;
    }
}

我编写了一个测试,将一个有效的Person对象写入文件,然后将其读回Person个对象。我的测试是

@Test
    public void writeAndReadPersonAsJsonOnFile() throws Exception {
        Address address = new Address("1 Infinite Loop", "Cupertino", "CA", 95014, "USA");
        String phone = "1-800-My-Apple";
        Person person = new Person("john", "doe", 21, Optional.of(address), Optional.of(phone));
        ObjectMapper objectMapper = registerJdkModuleAndGetMapper();
        File file = temporaryFolder.newFile("person.json");
        objectMapper.writeValue(file, person);

        assertTrue(file.exists());
        assertTrue(file.length() > 0);

        Person personFromFile = objectMapper.readValue(file, Person.class);
        assertEquals(person, personFromFile);

    }

    private ObjectMapper registerJdkModuleAndGetMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new Jdk8Module());
        return objectMapper;
    }

作为测试的一部分创建的file具有以下内容

{
    "firstName": "john",
    "lastName": "doe",
    "age": 21,
    "address": {
        "street": "1 Infinite Loop",
        "city": "Cupertino",
        "state": "CA",
        "zip": 95014,
        "country": "USA"
    },
    "phone": "1-800-My-Apple"
}

但在回读时,我得到personFromFile,看起来像是

personFromFile = {Person@1178} 
 firstName = "john"
 lastName = "doe"
 age = 21
 address = null
 phone = null

如您所见,addressphone它们都为空,即使它们存在于文件中。

这里有什么问题?

更新 代码库是https://github.com/101bits/java8-optional-json。这也包含失败的测试

2 个答案:

答案 0 :(得分:2)

尝试使用@JsonCreator标记其中一个构造函数,告诉Jackson使用哪个构造函数。注意:这还要求您使用@JsonProperty

标记每个构造函数的参数

当你希望杰克逊使用构造函数或工厂方法构建构造对象而不是杰克逊使用setter或公共(非最终)字段时,你should use the @JsonCreator annotation

此外,在您对Person和Address

重写“equals”之前,您的测试不会通过
public class Person {
    private String firstName;
    private String lastName;
    private int age;
    private Optional<Address> address;
    private Optional<String> phone;

    public Person(String firstName, String lastName, int age) {
        this(firstName, lastName, age, Optional.empty(), Optional.empty());
    }

    @JsonCreator
    public Person(
            @JsonProperty("firstName") String firstName,
            @JsonProperty("lastName") String lastName,
            @JsonProperty("age") int age,
            @JsonProperty("address") Optional<Address> address,
            @JsonProperty("phone") Optional<String> phone) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.address = address;
        this.phone = phone;
    }

通过测试更新:Pull Request

答案 1 :(得分:0)

据我所知,可选不会被序列化,因此,反序列化时,如果使用默认的java序列化,则不会获得值。但是,如果您使用序列化,那应该没问题。

请参阅此链接以获取更多详细信息: Why java.util.Optional is not Serializable, how to serialize the object with such fields