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

Java 当字段为可选字段时,jackson不会从json读回数据,java,json,java-8,jackson,optional,Java,Json,Java 8,Jackson,Optional,我正在使用Java8执行此任务。我还使用JDK8数据类型处理以下依赖项 <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jdk8</artifactId> <version>2.6.3</versi

我正在使用
Java8
执行此任务。我还使用
JDK8
数据类型处理以下依赖项

        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jdk8</artifactId>
            <version>2.6.3</version>
        </dependency>
我编写了一个测试,将一个有效的
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;
    }
作为测试的一部分创建的
文件有以下内容

{
    "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
如您所见,
地址
电话
都是空的,即使它们存在于文件中

这里怎么了

更新
代码库是。这还包含失败的测试

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

当您希望Jackson使用构造函数或工厂方法来构造对象,而不是让Jackson使用setter或公共(非最终)字段时,您可以使用

此外,除非您为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;
    }
公共类人物{
私有字符串名;
私有字符串lastName;
私人互联网;

通过测试的private-Optional

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

当您希望Jackson使用构造函数或工厂方法来构造对象,而不是让Jackson使用setter或公共(非最终)字段时,您可以使用

此外,除非您为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;
    }
公共类人物{
私有字符串名;
私有字符串lastName;
私人互联网;

private Optional with passing tests

据我所知,Optional不会序列化,因此,如果使用默认java序列化,则在反序列化时不会获得值。但是,如果使用序列化,则应该可以

有关更多详细信息,请参阅此链接:

据我所知,optional不会序列化,因此,如果使用默认java序列化,则在反序列化时不会获得值。但是,如果使用序列化,则应该可以

有关更多详细信息,请参阅此链接:

你的例子对我来说失败了,因为
地址中缺少构造函数。你确定你这里有完整的代码吗?我刚刚添加了到codebase的链接,也尝试了你所说的,但它不起作用。可能是使用3-arg构造函数。试着用
@JsonCreator
标记你的构造函数。你能发布失败消息吗从JUnit开始设置?这里真正的问题是
@JsonIgnore
。摆脱它,你不需要它。你的例子对我来说失败了,因为
Address
中缺少构造函数。你确定这里有完整的代码吗?我刚刚添加了到codebase的链接,也尝试了你所说的,但它不起作用。它可能使用了3-arg构造函数。试着用
@JsonCreator
标记你的构造函数。你能发布你从JUnit得到的失败吗?这里真正的问题是
@JsonIgnore
。摆脱它,你不需要它。考虑到它们的编辑,你能解释一下这会有什么不同吗?
@JsonProperty
参数的一个替代方法是使用。我不知道参数名称模块,谢谢@shmosel@SotiriosDelimanolis我为链接添加了代码示例和文档链接谢谢。但是,这里严格来说不需要
@JsonCreator
。只要有无参数构造函数和适当的属性描述符,这就行了。你能解释一下这会起什么作用吗不同的是,考虑到他们的编辑?除了
@JsonProperty
参数之外,另一种选择是使用。我不知道参数名称模块,谢谢@shmosel@SotiriosDelimanolis我为链接添加了代码示例和文档链接hanks。但是,这里并不严格需要
@JsonCreator
。只要有无参数构造函数和适当的属性描述符,这将起作用。
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;
    }