jackson-databind: Deserialization wrong when using a generic class with a converter as a property
Describe the bug Here are three classes and two converters
@NoArg
class OuterClass(
val inner: TestClassOri<Int, String>,
)
@NoArg
@JsonSerialize(converter = TestClassConverter::class)
@JsonDeserialize(converter = TestClassOriConverter::class)
class TestClassOri<T, K>(
val name: T,
val nameMap: HashMap<T, K>,
)
@NoArg
class TestClass<T, K>(val hashMap: HashMap<T, HashMap<T, K>>)
class TestClassConverter<T, K> : StdConverter<TestClassOri<T, K>, TestClass<T, K>>() {
override fun convert(value: TestClassOri<T, K>): TestClass<T, K> {
return TestClass(hashMapOf(value.name to value.nameMap))
}
}
class TestClassOriConverter<T, K> : StdConverter<TestClass<T, K>, TestClassOri<T, K>>() {
override fun convert(value: TestClass<T, K>): TestClassOri<T, K> {
val (name, map) = value.hashMap.entries.first()
return TestClassOri(name, map)
}
}
when deserialize the OuterClass
, the generic type of OuterClass.inner.nameMap
will be HashMap<String, String>
but not HashMap<Int, String>
which is expected.
Version information Which Jackson version(s) was this for? 2.14.2
@Test
fun testDeserialize() {
val jsonMapper = jsonMapper()
val jsonHashMap = jsonMapper.writeValueAsString(
OuterClass(TestClassOri(1, hashMapOf(1 to "1", 12 to "12")))
)
val de = jsonMapper.readerFor(OuterClass::class.java)
.readValue<OuterClass>(jsonHashMap)
assertEquals(de.inner.nameMap.keys.first()::class.java, Int::class.java)
}
org.opentest4j.AssertionFailedError: expected: <java.lang.String> but was: <int>
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 21 (10 by maintainers)
@yihtserns ,thanks a lot,
ContextualDeserializer
can really indeed solve the problem.The illustration above is what I think happened:
Converter
s don’t have “context” about what they’re processing, they just take INPUT and convert it into OUTPUT.<K>
or<V>
or<Whatever>
on aConverter
is just equivalent to declaring<Object>
.Only parameterized types are useful on a
Converter
, e.g. if you do this:…your problem will be solved, but I think you don’t want that. You’re probably type-parameterizing
TestClassOri
differently in different places, e.g.Deserializing with “context”
As mentioned above, (I think)
Converter
API does not have any “context” of what they’re converting - they don’t have info about the “target” e.g. the target field during deserialization.To access that information, you need to use StdDeserializer + ContextualDeserializer API: