为什么 ProjectionFactory 将 null 转换为空 Optionals?
Why does ProjectionFactory convert nulls to empty Optionals?
最近我将我的项目从 Spring Boot 2.1.0 更新到 Spring Boot 2.5.6。从那时起,我看到了 JSON 序列化的差异。
区分情况 (a) 任意值、(b) 显式 null 和 (c) 没有价值 我使用java.util.Optional
和杰克逊的@JsonInclude(NON_NULL)
注释。此外,我使用 Spring Data JPA 的投影模式来定义 JSON 格式,如下所示:
public interface MyProjection {
@JsonInclude(Include.NON_NULL)
Optional<String> getMyAttribute();
}
这与 Spring Boot 2.1.0 完美配合。
Field value
Rendered JSON
Optional.of("something")
{ "myAttribute": "something" }
Optional.empty()
{ "myAttribute": null }
null
{}
截至目前(在我更新到 Spring Boot 2.5.6 之后)null
呈现为 Optional.empty()
:
Field value
Rendered JSON
Optional.of("something")
{ "myAttribute": "something" }
Optional.empty()
{ "myAttribute": null }
null
{ "myAttribute": null }
我的第一个假设是杰克逊的 NON_NULL
不再与 Optional
一起正常工作。但事实并非如此。正如@Pedro 所说,它工作正常。经过一番调查后,我发现 Spring 的 ProjectionFactory
似乎处理 null
不同的值。它将 null
转换为 Optional.empty()
,而它以前没有这样做。
我想要恢复以前的行为。有谁知道如何防止 Spring 将空值转换为空的 Optionals 而不是将其保留为空值?是否有新的默认配置?我没找到。
我已经使用 @JsonSerialize(include = Inclusion.NON_NULL)
解决了这个问题并且它起作用了。
经过几次搜索,我找到了感兴趣的测试用例。
以下是 jackson 项目中可选的测试用例的摘录:
public void testConfigAbsentsAsNullsTrue() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module().configureAbsentsAsNulls(true));
OptionalData data = new OptionalData();
String value = mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL).writeValueAsString(data);
assertEquals("{}", value);
}
public void testConfigAbsentsAsNullsFalse() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module().configureAbsentsAsNulls(false));
OptionalData data = new OptionalData();
String value = mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL).writeValueAsString(data);
assertEquals("{\"myString\":null}", value);
}
class OptionalData {
public Optional<String> myString = Optional.empty();
}
单元测试可选Link:
并且有一个注释configureAbsentsAsNulls。
https://github.com/FasterXML/jackson-datatype-jdk8/blob/master/src/main/java/com/fasterxml/jackson/datatype/jdk8/Jdk8Module.java
For compatibility with older versions
* of other "optional" values (like Guava optionals), it can be set to 'true'. The
* default is `false` for backwards compatibility.
public Jdk8Module configureAbsentsAsNulls(boolean state) {
_cfgHandleAbsentAsNull = state;
return this;
}
所以你只需要设置 configureAbsentsAsNulls(true) 来回滚你之前的状态。
有三种方法可以忽略1)处的空字段。场级 2)。 Class 3 级)。全球
@JsonInclude(Include.NON_NULL)
私有字符串用户名;
@JsonInclude(Include.NON_NULL)
public class Book implements Comparable<Book> {
private String title;
private String author;
private int price;
public Book(String title, String author, int price) {
this.title = title;
this.author = author;
this.price = price;
}
}
// let's create a book with author as null
Book book = new Book(null, null, 42);
ObjectMapper mapper = new ObjectMapper();
// configure ObjectMapper to exclude null fields whiel serializing
mapper.setSerializationInclusion(Include.NON_NULL);
String json =mapper.writeValueAsString(cleanCode);
System.out.println(json);
看来我不能再使用 java.util.Optional
了。 Spring 开发人员扩展了 ProjectingMethodInterceptor
to convert null
values into the empty representation of the used wrapper type(在我的例子中是 Optional.empty()
)。
这也适用于其他包装器类型:
com.google.common.base.Optional
scala.Option
io.vavr.control.Option
最近我将我的项目从 Spring Boot 2.1.0 更新到 Spring Boot 2.5.6。从那时起,我看到了 JSON 序列化的差异。
区分情况 (a) 任意值、(b) 显式 null 和 (c) 没有价值 我使用java.util.Optional
和杰克逊的@JsonInclude(NON_NULL)
注释。此外,我使用 Spring Data JPA 的投影模式来定义 JSON 格式,如下所示:
public interface MyProjection {
@JsonInclude(Include.NON_NULL)
Optional<String> getMyAttribute();
}
这与 Spring Boot 2.1.0 完美配合。
Field value | Rendered JSON |
---|---|
Optional.of("something") |
{ "myAttribute": "something" } |
Optional.empty() |
{ "myAttribute": null } |
null |
{} |
截至目前(在我更新到 Spring Boot 2.5.6 之后)null
呈现为 Optional.empty()
:
Field value | Rendered JSON |
---|---|
Optional.of("something") |
{ "myAttribute": "something" } |
Optional.empty() |
{ "myAttribute": null } |
null |
{ "myAttribute": null } |
我的第一个假设是杰克逊的 NON_NULL
不再与 Optional
一起正常工作。但事实并非如此。正如@Pedro 所说,它工作正常。经过一番调查后,我发现 Spring 的 ProjectionFactory
似乎处理 null
不同的值。它将 null
转换为 Optional.empty()
,而它以前没有这样做。
我想要恢复以前的行为。有谁知道如何防止 Spring 将空值转换为空的 Optionals 而不是将其保留为空值?是否有新的默认配置?我没找到。
我已经使用 @JsonSerialize(include = Inclusion.NON_NULL)
解决了这个问题并且它起作用了。
经过几次搜索,我找到了感兴趣的测试用例。
以下是 jackson 项目中可选的测试用例的摘录:
public void testConfigAbsentsAsNullsTrue() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module().configureAbsentsAsNulls(true));
OptionalData data = new OptionalData();
String value = mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL).writeValueAsString(data);
assertEquals("{}", value);
}
public void testConfigAbsentsAsNullsFalse() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module().configureAbsentsAsNulls(false));
OptionalData data = new OptionalData();
String value = mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL).writeValueAsString(data);
assertEquals("{\"myString\":null}", value);
}
class OptionalData {
public Optional<String> myString = Optional.empty();
}
单元测试可选Link:
并且有一个注释configureAbsentsAsNulls。 https://github.com/FasterXML/jackson-datatype-jdk8/blob/master/src/main/java/com/fasterxml/jackson/datatype/jdk8/Jdk8Module.java
For compatibility with older versions
* of other "optional" values (like Guava optionals), it can be set to 'true'. The
* default is `false` for backwards compatibility.
public Jdk8Module configureAbsentsAsNulls(boolean state) {
_cfgHandleAbsentAsNull = state;
return this;
}
所以你只需要设置 configureAbsentsAsNulls(true) 来回滚你之前的状态。
有三种方法可以忽略1)处的空字段。场级 2)。 Class 3 级)。全球
@JsonInclude(Include.NON_NULL) 私有字符串用户名;
@JsonInclude(Include.NON_NULL)
public class Book implements Comparable<Book> {
private String title;
private String author;
private int price;
public Book(String title, String author, int price) {
this.title = title;
this.author = author;
this.price = price;
}
}
// let's create a book with author as null
Book book = new Book(null, null, 42);
ObjectMapper mapper = new ObjectMapper();
// configure ObjectMapper to exclude null fields whiel serializing
mapper.setSerializationInclusion(Include.NON_NULL);
String json =mapper.writeValueAsString(cleanCode);
System.out.println(json);
看来我不能再使用 java.util.Optional
了。 Spring 开发人员扩展了 ProjectingMethodInterceptor
to convert null
values into the empty representation of the used wrapper type(在我的例子中是 Optional.empty()
)。
这也适用于其他包装器类型:
com.google.common.base.Optional
scala.Option
io.vavr.control.Option