Reputation: 382
I have a data https://gist.githubusercontent.com/iva-nova-e-katerina/fc1067e971c71a73a0b525a21b336694/raw/954477261bb5ac2f52cee07a8bc45a2a27de1a8c/data2.json a List with seven CheckResultItem elements. I trying to parse them this way:
import com.fasterxml.jackson.module.kotlin.readValue
...
val res = restHelper.objectMapper.readValue<List<CheckResultItem>>(text)
which gives me the following error:
com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException: Instantiation of [simple type, class com.fmetric.validation.api.Brick] value failed for JSON property upperLevelBricks due to missing (therefore NULL) value for creator parameter upperLevelBricks which is a non-nullable type
at [Source: (StringReader); line: 1, column: 714] (through reference chain: java.util.ArrayList[0]->com.fmetric.validation.api.checking.CheckResultItem["brick"]->com.fmetric.validation.api.Brick["upperLevelBricks"])
at com.fasterxml.jackson.module.kotlin.KotlinValueInstantiator.createFromObjectWith(KotlinValueInstantiator.kt:116)
There is @JsonIgnore annotation in data class :
data class Brick(
val id: UUID?,
val name: String,
val type: BrickType,
val propertyValues: List<ProjectBrickPropertyValue<*>>,
@JsonIgnore
val upperLevelBricks: ArrayList<Brick>,
val downLevelBricks: ArrayList<Brick>,
var drawingDetails: List<BrickDrawingDetails>?
) {
But it seems it doesn't work. Could you explain me what is wrong?
UPD: Also I have tried @JsonIgnoreProperties({"upperLevelBricks"})
class annotation but it doesn't work. My solution was to set a default value
val upperLevelBricks: ArrayList<Brick> = arrayListOf(),
But I think that annotations should work!
Upvotes: 0
Views: 1822
Reputation: 7902
Actually, it works, but not the way you think. During deserialization @JsonIgnore
ignores the respectful field in JSON, like it wasn't there (but it's doesn't make sense in this case, because it's initially absent in JSON).
In Java, Jackson would've just instantiated class with null
value for the absent field (because all object types in Java are nullable, which means they allow the value to be set to null
). But in Kotlin, a property should be explicitly marked as nullable (val upperLevelBricks: List<Brick>?
) or have a default value (val upperLevelBricks: List<Brick> = emptyList()
) so that Jackson could create a class instance in this case.
Note that approach with default value for property won't work (unless you additionally mark it with @JsonIgnore
) if this field is present in JSON but explicitly set to null
:
{
...
"upperLevelBricks": null,
...
}
Anyway, if you don't want to change the API of your Brick
class you may provide a default value for this field only when it's created during Jackson deserialization (and only if it's absent/null
in JSON) via custom deserializer:
object EmptyListAsDefault : JsonDeserializer<List<Brick>>() {
override fun deserialize(jsonParser: JsonParser, context: DeserializationContext): List<Brick> =
jsonParser.codec.readValue(
jsonParser,
context.typeFactory.constructCollectionType(List::class.java, Brick::class.java)
)
override fun getNullValue(context: DeserializationContext): List<Brick> = emptyList()
}
data class Brick(
//...
@JsonDeserialize(using = EmptyListAsDefault::class)
val upperLevelBricks: List<Brick>,
//...
)
Upvotes: 1