当字段为可选时,杰克逊不会从 json 读回数据
jackson does not read back data from json when fields are Optional
我正在使用 Java 8
来执行此任务。我还关注 JDK8
数据类型的依赖性工作。
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.6.3</version>
</dependency>
我有一个 class 看起来像
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
如您所见,address
和 phone
它们都是空的,即使它们存在于文件中。
这里有什么问题?
更新
代码库是 https://github.com/101bits/java8-optional-json。这也包含失败的测试
尝试用@JsonCreator 标记其中一个构造函数,以告诉 Jackson 使用哪个构造函数。注意:这还需要你用 @JsonProperty
标记每个构造函数的参数
当您希望 Jackson 使用构造函数或工厂方法构造对象而不是让 Jackson 使用 setter 或 public(非最终)字段时,您 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 通过测试
据我所知,optional 不会被序列化,因此,如果您使用默认的 java 序列化,则在反序列化时您不会获得值。但是,如果您使用序列化,应该没问题。
请参阅此 link 了解更多详情:
Why java.util.Optional is not Serializable, how to serialize the object with such fields
我正在使用 Java 8
来执行此任务。我还关注 JDK8
数据类型的依赖性工作。
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.6.3</version>
</dependency>
我有一个 class 看起来像
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
如您所见,address
和 phone
它们都是空的,即使它们存在于文件中。
这里有什么问题?
更新 代码库是 https://github.com/101bits/java8-optional-json。这也包含失败的测试
尝试用@JsonCreator 标记其中一个构造函数,以告诉 Jackson 使用哪个构造函数。注意:这还需要你用 @JsonProperty
标记每个构造函数的参数当您希望 Jackson 使用构造函数或工厂方法构造对象而不是让 Jackson 使用 setter 或 public(非最终)字段时,您 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 通过测试
据我所知,optional 不会被序列化,因此,如果您使用默认的 java 序列化,则在反序列化时您不会获得值。但是,如果您使用序列化,应该没问题。
请参阅此 link 了解更多详情: Why java.util.Optional is not Serializable, how to serialize the object with such fields