Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The readValue fails for maps with inline-value-class as key #825

Closed
2 of 3 tasks
TobseF opened this issue Aug 12, 2024 · 2 comments
Closed
2 of 3 tasks

The readValue fails for maps with inline-value-class as key #825

TobseF opened this issue Aug 12, 2024 · 2 comments
Labels

Comments

@TobseF
Copy link

TobseF commented Aug 12, 2024

Search before asking

Describe the bug

Using a Kotlin inline-value-class a key in map breaks the Jackson serialization.
For example, it's not possible to read a map of type Map<Index, Int> where Index is a value class:

@JvmInline
value class Index(val value: Int = 0)

                       // ↱ the `map` uses a value class `Index` as key
data class FooMapKey(val map : MutableMap<Index, Int> = mutableMapOf())

Reading a JSON file with such a map fails:

val mapper = jacksonObjectMapper().registerKotlinModule()
        
val fooJson = "{ "map": { "1": 42 } }"
val readValue = mapper.readValue<FooField>(fooJson) // ⚡`Cannot find a (Map) Key deserializer `

It fails during readValue(json) with the error:

Cannot find a (Map) Key deserializer for type [simple type, class de.itscope.catalog.pricelist.ParseValueClassTest$Index]
 at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1]
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot find a (Map) Key deserializer for type [simple type, class de.itscope.catalog.pricelist.ParseValueClassTest$Index]
 at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1]
	at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)

It's does not belong to the input. It even fails if the map is empty:

{
  "map" : { }
}

Using a value class as map-key, helps a lot to make map access type safe and improve the readability of code.
The other way around already works — Using the value class as value. So it's possible to save this class:

data class FooMapValue(val map : MutableMap<Int, Index> = mutableMapOf())

To Reproduce

@Test
fun parseFooMapTest(){
    val mapper = jacksonObjectMapper().registerKotlinModule()

    val foo = FooMapKey().apply {
        map[Index(1)] = 42
    }
    val fooJson = mapper.writeValueAsString(foo)
    val readValue = mapper.readValue<FooMapKey>(fooJson)   // ⚡`Cannot find a (Map) Key deserializer `

    assertEquals(foo, readValue)
}

Expected behavior

The mapper.readValue<FooMapKey>(fooJson) should read the JSON and deserialize into a FooMapKey.

Versions

Kotlin: 2.0.0
Jackson-module-kotlin: 2.17.2
Jackson-databind: 2.17.2

Additional context

You can find a detailed test example for the problem here:
ParseValueClassMapTest.kt

@TobseF TobseF added the bug label Aug 12, 2024
@cowtowncoder
Copy link
Member

Correct: for now, you need to register a key deserializer for things other than basic scalar JDK types (Strings, primitives/wrappers, Enums).

@k163377
Copy link
Contributor

k163377 commented Aug 22, 2024

@TobseF
At present, key deserialisers have to be defined manually.
There are many dependencies on specific implementations, but the following work except in edge cases.
https://github.com/ProjectMapK/jackson-module-kogera/pull/224/files#diff-b03a6f91081da3aa22c53b161b0a2f6f1a0cf4ba318329907046b5f5335b17c8

By the way, if the content is a complete duplication, could you close it?

@TobseF TobseF closed this as completed Aug 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants