Druckles
Druckles

Reputation: 3782

What does Spring use to do deserialization?

I have the following class:

data class Thing(val lines: List<String>)

The JSON representation is:

{
    "lines": [
        "something",
        "something else"
    ]
}

Spring WebFlux can successfully parse this with the following:

// Parse the JSON as an object and return it.
request -> ServerResponse.ok().body(request.bodyToMono(Thing::class.java)

However, using Jackson directly with either of the following techniques fails:

val mapper = ObjectMapper()
val item = mapper.readValue<Thing>("""{"lines":["something","something else"]}""")
ServerResponse.ok().body(request.bodyToMono(Map::class.java)
        .map { map ->
            val mapper = ObjectMapper()
            val tmp = mapper.convertValue(map, Thing::class.java)
        }

The error is:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `Thing` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

I thought that Spring was using Jackson to do its transformation. And I thought that Jackson could cope with such basic transformations from JSON -> POJOs. Using a @JsonDeserialize class obviously works. So why does the first example work and the second not?

Upvotes: 0

Views: 440

Answers (1)

Faron
Faron

Reputation: 1393

Spring uses Jackson but it registers custom handlers and modules when it creates its default instance of ObjectMapper.

Jackson has special handling for constructors that take a single argument. This was done to support classes like UUID and URI. To instruct Jackson to not use this technique, annotate your constructor with @JsonCreator.

data class Thing @JsonCreator constructor(val lines: List<String>)

I have not reviewed Spring's reactive code so I do not know what or if it does something to disable Jackson's special handling.

Upvotes: 2

Related Questions