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

@JsonAnySetter not working since 2.18, what is the correct usage? #832

Open
jacinpoz opened this issue Sep 30, 2024 · 4 comments
Open

@JsonAnySetter not working since 2.18, what is the correct usage? #832

jacinpoz opened this issue Sep 30, 2024 · 4 comments
Labels

Comments

@jacinpoz
Copy link

jacinpoz commented Sep 30, 2024

Your question

Since the upgrade to 2.18.0 from 2.17.2 our data classes constructor properties are not deserialized correctly.

See sample code below:

class TestAnySetter {
    data class AnySetter @JvmOverloads constructor(
        val test : String? = null,
        @field:JsonAnySetter
        @get:JsonAnyGetter
        val anything: Map<String, Any?> = mutableMapOf(),
    )

    @Test
    fun testDeserialization() {
        val json = """
            {
                "widget": {
                    "debug": "on"
                 }
             }     """.trimMargin()
        val jacksonMapper = ObjectMapper()
        jacksonMapper.registerModules(KotlinModule.Builder().build())
        val anySetter = jacksonMapper.readValue<AnySetter>(json)
        assertEquals("widget", anySetter.anything.entries.first().key)
    }
}

This test passes in 2.17.2, but in 2.18 the "anything" property in "anySetter" variable doesn't contain any entries in the map and therefore it throws a java.util.NoSuchElementException.

Additionally, when we upgraded to 2.17, we had to change all references to @JsonAnySetter in our constructor properties to be @field:JsonAnySetter as otherwise no json properties would be deserialized. Now none of these approaches in 2.18 work.

What is the correct way of using @JsonAnySetter in constructor properties now?

PS: I also played with the @JsonCreator annotation given the contents of https://cowtowncoder.medium.com/jackson-2-18-rc1-overview-765e29a33371 , but it made no difference.

@cowtowncoder
Copy link
Member

@jacinpoz This might be due to:

FasterXML/jackson-databind#4508

and if so, it'd be fixed for 2.18.1. If there is any chance you could try locally building and using 2.18.1-SNAPSHOT of jackson-databind, that'd be great. To rule fix in (or out).

Breakage in 2.18.0 was uncaught because it appears that:

  1. This is not a use case covered by any of Kotlin module unit tests (contributions welcome!)
  2. No one with this use case tried out 2.18.0-rc1 version that was available before final 2.18.0

@jacinpoz
Copy link
Author

jacinpoz commented Oct 1, 2024

@cowtowncoder Thank you for the very quick response!

I have tested locally with jackson-databind 2.18.1 and it seems to work well when using @JsonAnySetter , although it doesn't work anymore with @field:JsonAnySetter . So basically we are back to the same behaviour we had in 2.16, which is fine by me!

Thanks again for the rapid reply, and I am looking forward to seeing 2.18.1 released.

@chad-moller-target
Copy link

@jacinpoz for the benefit of others who find this bug, would you be willing to share the example code that works with 2.18.1-SNAPSHOT?

@jacinpoz
Copy link
Author

jacinpoz commented Oct 1, 2024

Sure, it's just the exact same code as the one in my first example, but replacing @field:JsonAnySetter for @JsonAnySetter. See code below:

class TestAnySetter {
    data class AnySetter @JvmOverloads constructor(
        val test : String? = null,
        @JsonAnySetter
        @get:JsonAnyGetter
        val anything: Map<String, Any?> = mutableMapOf(),
    )

    @Test
    fun testDeserialization() {
        val json = """
            {
                "widget": {
                    "debug": "on"
                 }
             }     """.trimMargin()
        val jacksonMapper = ObjectMapper()
        jacksonMapper.registerModules(KotlinModule.Builder().build())
        val anySetter = jacksonMapper.readValue<AnySetter>(json)
        assertEquals("widget", anySetter.anything.entries.first().key)
    }
}

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