Search code examples
javaspring-bootjacksonjson-schema-validatorjackson2

Jackson (de)serialization not accurate between HTTP responses and test cases


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.


Solution

  • Disable the DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, so that Jackson doesn‘t deserialize empty arrays as null values