使用 Jackson / Springboot 解析 Optional<T> 时出错
Error parsing Optional<T> with Jackson / Springboot
我有一个 class 并且更愿意使用值 Optional<T>
例如 Optional<Integer> value;
.
在这个项目中 Springboot
用于创建网络控制器,客户端通过 json
发送/接收。
客户端put或者post时,解析java
中的class有Optional<T>
类型参数,失败;否则它工作正常。然而; Optional<T>
是首选,因为我们希望客户端能够在不使用字段时省略它们。
例如:
这个有效:
public class TestClass {
private final int testValue;
public TestClass(@JsonProperty("testValue") int testValue) {
this.testValue = testValue;
}
public int getTestValue() {
return testValue;
}
}
这不是:
public class TestClass {
private final Optional<Integer> testValue;
public TestClass(@JsonProperty("testValue") Optional<Integer> testValue) {
this.testValue = testValue;
}
public Optional<Integer> getTestValue() {
return testValue;
}
}
以下是来自 Gradle.
的一些版本行
springBootVersion = '1.5.8.RELEASE'
compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.6.4'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: '2.6.3'
当使用 Postman 进行 POST 且值为 int
时,一切正常。当我使用 Optional<Integer>
时,我从网络调用中收到以下错误响应。
总结:
"exception":
"org.springframework.http.converter.HttpMessageNotReadableException",
"message": "JSON parse error: 0; nested exception is
com.fasterxml.jackson.databind.JsonMappingException: 0 (through
reference chain:
…(my class path)… [\"actions\"]->java.util.ArrayList[3])",
您需要将第二个示例更改为
public TestClass(@JsonProperty("testValue") int testValue) {
this.testValue = Optional.of(testValue);
}
有一个 Jackson 模块可以帮助 serialize/deserialize Optional
参数。
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.9.6</version>
</dependency>
然后使用您的 ObjectMapper
:
注册模块
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module());
java.util.Optional 不可序列化
可选意味着不一定有您要找的对象!所以你可以简单地使用一个包装器。您可以 return 对象(如果对象存在),或者如果您的对象不存在,您可以 return 404 状态。
public static <X> ResponseEntity<X> wrapOrNotFound(Optional<X> maybeResponse, HttpHeaders header) {
return maybeResponse.map(response -> ResponseEntity.ok().headers(header).body(response))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
在不更改任何现有代码的情况下将 Jackson 升级到版本 2.8.6
修复了它。
我确实按照上面的另一个答案,奇怪的是,升级到更高版本的'2.9.6'没有用。然而,它确实给了我一条新的错误消息,最终导致我进入一个线程,其他人也必须降级。
我有一个 class 并且更愿意使用值 Optional<T>
例如 Optional<Integer> value;
.
在这个项目中 Springboot
用于创建网络控制器,客户端通过 json
发送/接收。
客户端put或者post时,解析java
中的class有Optional<T>
类型参数,失败;否则它工作正常。然而; Optional<T>
是首选,因为我们希望客户端能够在不使用字段时省略它们。
例如:
这个有效:
public class TestClass {
private final int testValue;
public TestClass(@JsonProperty("testValue") int testValue) {
this.testValue = testValue;
}
public int getTestValue() {
return testValue;
}
}
这不是:
public class TestClass {
private final Optional<Integer> testValue;
public TestClass(@JsonProperty("testValue") Optional<Integer> testValue) {
this.testValue = testValue;
}
public Optional<Integer> getTestValue() {
return testValue;
}
}
以下是来自 Gradle.
的一些版本行springBootVersion = '1.5.8.RELEASE'
compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.6.4'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: '2.6.3'
当使用 Postman 进行 POST 且值为 int
时,一切正常。当我使用 Optional<Integer>
时,我从网络调用中收到以下错误响应。
总结:
"exception": "org.springframework.http.converter.HttpMessageNotReadableException", "message": "JSON parse error: 0; nested exception is com.fasterxml.jackson.databind.JsonMappingException: 0 (through reference chain: …(my class path)… [\"actions\"]->java.util.ArrayList[3])",
您需要将第二个示例更改为
public TestClass(@JsonProperty("testValue") int testValue) {
this.testValue = Optional.of(testValue);
}
有一个 Jackson 模块可以帮助 serialize/deserialize Optional
参数。
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.9.6</version>
</dependency>
然后使用您的 ObjectMapper
:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module());
java.util.Optional 不可序列化
可选意味着不一定有您要找的对象!所以你可以简单地使用一个包装器。您可以 return 对象(如果对象存在),或者如果您的对象不存在,您可以 return 404 状态。
public static <X> ResponseEntity<X> wrapOrNotFound(Optional<X> maybeResponse, HttpHeaders header) {
return maybeResponse.map(response -> ResponseEntity.ok().headers(header).body(response))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
在不更改任何现有代码的情况下将 Jackson 升级到版本 2.8.6
修复了它。
我确实按照上面的另一个答案,奇怪的是,升级到更高版本的'2.9.6'没有用。然而,它确实给了我一条新的错误消息,最终导致我进入一个线程,其他人也必须降级。