jackson-module-kotlin
jackson-module-kotlin copied to clipboard
Exception when using @JsonIdentityInfo
Describe the bug
The issue that I am facing similar to Issue 194 but extended.
When I try to use the similar setup but json value would not have id property ("{"name": "Foo"}") because that would be automatically created in constructor using UUID.randomUUID().
To Reproduce
class TestGithub571 {
private val id: UUID = UUID.fromString("149800a6-7855-4e09-9185-02e442da8013")
private val json = """{"name": "Foo"}"""
@Test
fun testIdentityInfo() {
val mapper = jacksonObjectMapper()
val value = mapper.readValue(json, WithIdentity::class.java)
assertEquals(id, value.id)
assertEquals("Foo", value.name)
}
@JsonIdentityInfo(
property = "id",
scope = WithIdentity::class,
generator = ObjectIdGenerators.PropertyGenerator::class
)
class WithIdentity(val id: UUID = UUID.randomUUID(),
val name: String)
@Test
fun testIdentityInfo_WithDefaultId() {
val mapper = jacksonObjectMapper()
val value = mapper.readValue(json, WithIdentityAndDefaultId::class.java)
assertEquals(id, value.id)
assertEquals("Foo", value.name)
}
@JsonIdentityInfo(
property = "id",
scope = WithIdentityAndDefaultId::class,
generator = ObjectIdGenerators.PropertyGenerator::class
)
class WithIdentityAndDefaultId(val id: UUID = UUID.fromString("149800a6-7855-4e09-9185-02e442da8013"),
val name: String)
}
Expected behavior
I expected the above test cases to get passed because the value for name is deserialized from json string and UUID is constructed from class constructor.
Versions Kotlin: 1.6.21 Jackson-module-kotlin: 2.13.2 Jackson-databind: 2.13.2.1
By specifying ObjectIdGenerators.None for generator, the deserialization appears to succeed.
https://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-annotations/latest/com/fasterxml/jackson/annotation/JsonIdentityInfo.html
companion object {
private val defaultId: UUID = UUID.fromString("149800a6-7855-4e09-9185-02e442da8013")
private const val json = """{"name": "Foo"}"""
}
@JsonIdentityInfo(
property = "id",
scope = WithIdentity::class,
generator = ObjectIdGenerators.None::class
)
class WithIdentity(val id: UUID = defaultId, val name: String)
@Test
fun testIdentityInfo() {
val mapper = jacksonObjectMapper()
val value = mapper.readValue(json, WithIdentity::class.java)
assertEquals(defaultId, value.id)
assertEquals("Foo", value.name)
}
However, I am not sure if this is the correct usage. I am not familiar with this feature, but from what I see in some of the samples, I think there is something wrong with what you are trying to do.
@cowtowncoder
Do you know how to achieve a use case like "when deserializing a class with JsonIdentityInfo, if there is no property with id in the JSON, generate a value for it" when using only databind?
@k163377 I can't think of an obvious way -- this is not a planned or supported usage for @JsonIdentityInfo. Identity is meant to be preserved on serialiation, reconstructed on deserialization; this is the canonical use case.
This is not to say there might not be some clever usage, or combination of settings, but I cannot immediately think of the way as it goes outside of planned usage.