So i want to deserialize a string into a `Data.Sin...
# announcements
s
So i want to deserialize a string into a
Data.Single
but it fails.
Copy code
sealed class Data<T: Any> {
    class Single<T: Any>(val single: T?): Data<T>()
    class ListOf<T: Any>(val list: List<T>): Data<T>()
}
Could the reason for the mismatch be that the constructor parameter
single
is nullable?? The error message is: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of
uk.co.whichdigital.pricingengine.Data$Single
(although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value (‘up and running’)
Here is my current jsonMapper config:
Copy code
private val jsonMapper = ObjectMapper().apply {
        registerModule(KotlinModule())
        configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    }
UPDATE: I changed the code to `Data.Single`’s generic parameter is nullable
class Single<T>(val single: T): Data<T>()
but the error message didn’t change.
d
With default configuration the representation for
Single
would be a JSON object:
Copy code
{
  "single": <value here>
}
If you just want the value, you can use
@JsonCreator
on the constructor and
@JsonValue
on the property.
s
give that this is the whole TypeDefiinition
class Single<T>(val single: T): Data<T>()
I guess the constructor is implicit and so annotated version would be
class Single<T>(@JsonValue val single: T): Data<T>()
!? The error message didn’t change. (no String-argument constructor/factory method to deserialize)
d
Well, you haven't annotated the constructor.
class Single<T> @JsonCreator constructor(@JsonValue val single: T) : Data<T>()
s
but now I did. no change 😐
d
let me check this...
Seems like its a problem with jackson-module-kotlin.
Without that my solution works
s
without the Kotlin module i’m running into problems with a data class 😕
Copy code
InvalidDefinitionException: Invalid type definition for type `uk.co.whichdigital.pricingengine.GraphQlResponse`: Argument #0 has no property name, is not Injectable: can not use as Creator [constructor for uk.co.whichdigital.pricingengine.GraphQlResponse, annotations: {interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}]
with
Copy code
data class GraphQlResponse<T, D: Data<T>>@JsonCreator constructor(
    @JsonValue val data: Map<String, D>?, 
    @JsonValue val errors: List<GraphQlError>?
)
d
Yes, seems like you need a custom deserializer to work around this
s
generic custom deserialisers?? 😨
I’ll check making GraphQlResponse a normal class
d
It's quite simple:
Copy code
class SingleDeserializer : StdConverter<String, Data.Single<String>>() {

    override fun convert(value: String?): Data.Single<String> {
        return Data.Single(value)
    }

}

@JsonDeserialize(converter = SingleDeserializer::class)
class Single<T: Any>(@JsonValue val single: T?): Data<T>()
s
actually the
data class
was fine. I had to add
@JsonProperty
to the fields 😮
@JsonProperty("data") val data: Map<String, D>?
The Data.Single deserialisation works without the KotlinModule.
So the simple case with String return value works now, it’d a good start! Thx 👍