英文:
Jackson (de)serialization not accurate between HTTP responses and test cases
问题
我有一个 Spring Boot 2.3.2.RELEASE
的 WebFlux 应用程序。我有一些 JPA 实体,它们作为 RESTful API 响应的一部分返回。
我使用 @WebFluxTest
的测试检查 HTTP 响应和契约,针对 JSON 架构进行检查。我在这些测试中注入了 Jackson 的 ObjectMapper
和 Spring 的 WebTestClient
,以便根据相应/预期的 JSON 架构检查 HTTP 响应。
问题是:如果在应用程序运行时使用任何 HTTP 客户端,没有元素的集合(在 Java 端)会被序列化为 JSON 的空数组 —— 无论理论上是否正确,我都期望是这样的;但是在测试用例中,相同的空集合被序列化为具有 null
值。
所以我想知道为什么会有这种不同?我期望在任何时候都得到相同的 JSON 字符串。
我知道我没有使用不同的 ObjectMapper
设置 —— 或者至少我认为没有。我没有为该类型有任何自定义的 Spring Bean,因此我使用的是 Spring Boot 默认注入的内容,所以无论是运行中的应用程序还是运行测试时都应该是相同的。关于 Jackson,唯一的定制是在 application.yml
文件中的应用程序级别完成的:
spring:
...
jackson:
property-naming-strategy: LOWER_CAMEL_CASE
serialization:
write-date-timestamps-as-nanoseconds: false
write-dates-as-timestamps: true
...
对于 JSON 架构实现,我使用的是
com.networknt:json-schema-validator:1.0.43
库。
以下是一个测试用例的摘录:
@WebFluxTest(controllers = [ExamController::class])
internal class ExamControllerTest {
@Autowired
private lateinit var webClient: WebTestClient
@Autowired
private lateinit var mapper: ObjectMapper
@Test
@Disabled
fun getById_ValidateResponseAgainstSchema() {
// 重要提示:如果您在此处进行任何更新,请同时对 getById_WhenRecordExists 进行相应的更改
webClient.get()
.uri("/exams/10001030")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk
.expectBody()
.consumeWith { result ->
val schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)
this::class.java.getResourceAsStream("/json-schemas/exam/exam-details.json").use {
Assertions.assertThat(schemaFactory.getSchema(it).validate(mapper.readTree(result.responseBody))).isEmpty()
}
}
}
// ...
}
测试数据是在使用 Testcontainers 中的 Docker 容器中创建/填充的。
英文:
I have a Spring Boot 2.3.2.RELEASE
WebFlux application. I have some JPA entities that are returned as part of the RESTful API responses.
The tests that I have (using @WebFluxTest
) check the HTTP response(s) and contract — against a JSON schema. I'm injecting a Jackson's ObjecMapper
and a Spring WebTestClient
in those tests to check the HTTP response(s) against the corresponding/expected JSON schema.
The problem is: if I use any HTTP client when the application is running, the collections (on the Java side) with no elements are serialized into JSON as empty arrays — that's what I would expect regardless of whether that's right or wrong theoretically; but on the test cases, the same empty collections are being serialized with null
values.
So I wonder why would that be different? I would expect the same JSON string at any point.
I know I'm not using different ObjectMapper
settings — or that's what I think. I don't have any custom Spring beans for that type, so I'm using whatever Spring Boot injects by default, so it must be the same for the running application as well as when running the tests. The only customization for Jackson is done at the application level in the application.yml
:
spring:
...
jackson:
property-naming-strategy: LOWER_CAMEL_CASE
serialization:
write-date-timestamps-as-nanoseconds: false
write-dates-as-timestamps: true
...
> I'm using the com.networknt:json-schema-validator:1.0.43
library for the JSON schema implementation.
Excerpt of one of the test cases:
@WebFluxTest(controllers = [ExamController::class])
internal class ExamControllerTest {
@Autowired
private lateinit var webClient: WebTestClient
@Autowired
private lateinit var mapper: ObjectMapper
@Test
@Disabled
fun getById_ValidateResponseAgainstSchema() {
// IMPORTANT: If you update anything here, make the corresponding changes also to getById_WhenRecordExists
webClient.get()
.uri("/exams/10001030")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk
.expectBody()
.consumeWith { result ->
val schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)
this::class.java.getResourceAsStream("/json-schemas/exam/exam-details.json").use {
Assertions.assertThat(schemaFactory.getSchema(it).validate(mapper.readTree(result.responseBody))).isEmpty()
}
}
}
// ...
}
The test data is created/seeded in a Docker container using Testcontainers.
答案1
得分: 1
禁用 DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT
,这样 Jackson 就不会将空数组反序列化为 null 值。
英文:
Disable the DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT
, so that Jackson doesn‘t deserialize empty arrays as null values
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论