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

Closed
jacinpoz opened this issue Sep 30, 2024 · 10 comments
Closed

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

jacinpoz opened this issue Sep 30, 2024 · 10 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)
    }
}

@chad-moller-target
Copy link

@jacinpoz Thank you fine sir!

@meoyawn
Copy link

meoyawn commented Oct 22, 2024

I'm actually getting this bug starting with 2.17. Works in 2.16.2

data class DownloaderOptions(
    val http_chunk_size: Long,

    @JsonAnySetter
    @JsonAnyGetter
    val unknown: MutableMap<String, Any> = HashMap(),
)

lberrymage added a commit to accrescent/parcelo that referenced this issue Oct 24, 2024
Running Parcelo in a container via our current Dockerfile revealed that
"uses-sdk" fields were not being parsed from applications' Android
manifests, effectively preventing app uploads since the targetSdk
property of uses-sdk is required by Parcelo. This bug wasn't caught
until now because it only seems to manifest itself when running via the
Dockerfile; running locally as in our recommended development
environment does not have the issue. The Jackson 2.18.0 upgrade has not
yet been included in a production release, so it's uncertain whether the
issue would have surfaced in our production environment.

We tracked the issue down to a regression in Jackson 2.18.0. The exact
cause is unknown. However, a number of seemingly related issues were
reported for Jackson 2.18.0 [1], so we plan to closely monitor those
issues and test upcoming Jackson releases carefully to prevent breakage.

[1]: See below:

- FasterXML/jackson-module-kotlin#841
- FasterXML/jackson-module-kotlin#842
- FasterXML/jackson-module-kotlin#843
- FasterXML/jackson-module-kotlin#832
- FasterXML/jackson-databind#4508
- FasterXML/jackson-databind#4752
lberrymage added a commit to accrescent/parcelo that referenced this issue Oct 27, 2024
Running Parcelo in a container via our current Dockerfile revealed that
"uses-sdk" fields were not being parsed from applications' Android
manifests, effectively preventing app uploads since the targetSdk
property of uses-sdk is required by Parcelo. This bug wasn't caught
until now because it only seems to manifest itself when running via the
Dockerfile; running locally as in our recommended development
environment does not have the issue. The Jackson 2.18.0 upgrade has not
yet been included in a production release, so it's uncertain whether the
issue would have surfaced in our production environment.

We tracked the issue down to a regression in Jackson 2.18.0. The exact
cause is unknown. However, a number of seemingly related issues were
reported for Jackson 2.18.0 [1], so we plan to closely monitor those
issues and test upcoming Jackson releases carefully to prevent breakage.

[1]: See below:

- FasterXML/jackson-module-kotlin#841
- FasterXML/jackson-module-kotlin#842
- FasterXML/jackson-module-kotlin#843
- FasterXML/jackson-module-kotlin#832
- FasterXML/jackson-databind#4508
- FasterXML/jackson-databind#4752
@chad-moller-target
Copy link

I see 2.18.1 was released but this bug was not closed. But it seems like it should be, yes?

@cowtowncoder
Copy link
Member

@chad-moller-target I think so, although it'd be great if someone could confirm working.

However.... given the long path, tentative verification with 2.18.1-SNAPSHOT, I think I can close this -- re-open if necessary.

@nclaveeoh
Copy link

My workaround for now...

    abstract class OtherPropertiesHolder(@get:JsonAnyGetter open val otherProperties: MutableMap<String, Any?> = hashMapOf()) {
        @JsonAnySetter
        fun add(property: String, value: Any?) {
            otherProperties[property] = value
        }
    }

@dinomite
Copy link
Member

dinomite commented Dec 17, 2024

I added @jacinpoz 's reproduction as a test in the 2.18 branch (1bf0ad7) and merged it forward

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

6 participants