In Kotlin, I'm using jackson (fasterxml) for parsing an endpoint response (JSON). It looks similar to this:
{
...
steps: [
{
"status":200,
"id":"A",
"data":{
"score":"10"
}
},
{
"status":200,
"id":"B",
"data": {
"dateOfBirth":"10-09-1994",
"fullname": "Peter",
...
}
},
{
"status":200,
"id":"C",
"data": {
"dateOfBirth": {
"value": "10-03-1993"
},
...
}
},
]
...
}
My code looks like this:
...
response.readEntity(DocumentResponse::class.java)
...
@JsonIgnoreProperties(ignoreUnknown = true)
data class DocumentResponse @JsonCreator constructor(
@JsonProperty("steps")
val steps: List<StepResponse>
)
data class StepResponse @JsonCreator constructor(
@JsonProperty("status")
val status: String,
@JsonProperty("id")
val id: String,
@JsonProperty("data")
val data: Data?
)
@JsonIgnoreProperties(ignoreUnknown = true)
class Data @JsonCreator constructor(
@JsonProperty("dateOfBirth")
val dateOfBirth: String?,
@JsonProperty("fullName")
val fullName: String?,
@JsonProperty("dni")
val dni: String?,
...
)
The problem is that data
can have multiple types, and I want to get this field from the JSON only when id is "B". When the JSON is retrieved and it's read, an error is thrown because it reads step with id "A" and dateOfBirth
is not found, so it throws the following error:
MistmatchedInputException: Cannot deserialize instance of string out of START_OBJECT token ...
Is possible to ignore the field data
if it doesn't match with the JSON format?
I want to read the JSON but the only data
that is relevant to me is the one related to a specific id!
I would say your best option is to use a custom deserializer for StepResponse
:
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonNode
class StepResponseDeserializer constructor(vc: Class<*>? = null) : StdDeserializer<StepResponse>(vc) {
override fun deserialize(jp: JsonParser, ctxt: DeserializationContext): StepResponse {
val node = jp.codec.readTree<JsonNode>(jp)
val status = node["status"].asText()
val id = node["id"].asText()
val data = if ("B" == id) {
val dataNode = node["data"]
val dateOfBirth = dataNode["status"].asText()
val fullName = dataNode["fullName"].asText()
val dni = dataNode["dni"].asText()
Data(dateOfBirth, fullName, dni)
} else null
return StepResponse(status, id, data)
}
}
You can register the deserializer directly on the class as follows:
@JsonDeserialize(using = StepResponseDeserializer.class)
data class StepResponse @JsonCreator constructor(
val status: String,
val id: String,
val data: Data?
)
As a side note, you can drop all the @JsonProperty
annotations given that they are only needed if the Java/Kotlin property name does not match the JSON property name.