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

Field order mismatch after serialization and deserialization #842

Closed
3 tasks done
arvgord opened this issue Oct 15, 2024 · 4 comments
Closed
3 tasks done

Field order mismatch after serialization and deserialization #842

arvgord opened this issue Oct 15, 2024 · 4 comments
Labels

Comments

@arvgord
Copy link

arvgord commented Oct 15, 2024

Search before asking

  • I searched in the issues and found nothing similar.
  • I searched in the issues of databind and other modules used and found nothing similar.
  • I have confirmed that the problem only occurs when using Kotlin.

Describe the bug

I am encountering a problem where the field order is not preserved after serializing and deserializing objects in Jackson.

I need access to only one specific field (transactionId), while I want to pass the remaining fields as they are, preserving the order in which they appear. I expected the transactionId field order might change, but I did not expect the order of the other fields (a, b, c) to change, especially in the second and third tests (SecondObject and ThirdObject). The data inside the c array is preserved in the expected order, but the surrounding fields are re-ordered.

To Reproduce

Tested Objects:

@JsonAutoDetect(
    fieldVisibility = JsonAutoDetect.Visibility.ANY,
    getterVisibility = JsonAutoDetect.Visibility.NONE
)
class FirstObject {
    @field:JsonAnySetter
    @field:JsonAnyGetter
    val data: Map<String, Any?> = LinkedHashMap()

    val transactionId: String
        get() = data["transactionId"] as String
}

@JsonAutoDetect(
    fieldVisibility = JsonAutoDetect.Visibility.ANY,
    getterVisibility = JsonAutoDetect.Visibility.NONE
)
class SecondObject(
    val transactionId: String
) {
    @field:JsonAnySetter
    @field:JsonAnyGetter
    val data: Map<String, Any?> = LinkedHashMap()
}

@JsonAutoDetect(
    fieldVisibility = JsonAutoDetect.Visibility.ANY,
    getterVisibility = JsonAutoDetect.Visibility.NONE
)
class ThirdObject(
    val transactionId: String,
    @field:JsonAnySetter
    @field:JsonAnyGetter
    val data: Map<String, Any?> = LinkedHashMap()
)

Input JSON for tests:

{
  "b": 2,
  "a": 1,
  "transactionId": "test",
  "c": [
    {
      "id": "3",
      "value": "c"
    },
    {
      "id": "1",
      "value": "a"
    },
    {
      "id": "2",
      "value": "b"
    }
  ]
}

Test Case:

Here’s a test case to reproduce the issue. The following Kotlin test serializes and deserializes three different classes (FirstObject, SecondObject, and ThirdObject), comparing the serialized JSON with the original input JSON.
JacksonSortingTest.kt.

First Test Result (Passes):

The first test for FirstObject passes as expected, with the field order being preserved.

Failing Test Results:

Expected:

{
  "b": 2,
  "a": 1,
  "transactionId": "test",
  "c": [
    {
      "id": "3",
      "value": "c"
    },
    {
      "id": "1",
      "value": "a"
    },
    {
      "id": "2",
      "value": "b"
    }
  ]
}

For SecondObject was:

{
  "transactionId": "test",
  "a": 1,
  "b": 2,
  "c": [
    {
      "id": "3",
      "value": "c"
    },
    {
      "id": "1",
      "value": "a"
    },
    {
      "id": "2",
      "value": "b"
    }
  ]
}

For ThirdObject was:

{
  "transactionId": "test",
  "c": [
    {
      "id": "3",
      "value": "c"
    },
    {
      "id": "1",
      "value": "a"
    },
    {
      "id": "2",
      "value": "b"
    }
  ],
  "a": 1,
  "b": 2
}

Repository for Reproduction:
You can find a repository with the full reproduction of the issue at jackson-databind-sorting-issue.

Expected behavior

For SecondObject and ThirdObject, after serializing the object back to JSON, I expect the transactionId field to appear at the top, followed by the fields b, a, and c, in the exact order they were present when the JSON was deserialized into SecondObject and ThirdObject.

Versions

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

Additional context

This issue is a duplicate of 4751. I'm trying to reproduce it with Java, but it seems like all the described cases are specific to Kotlin

@cowtowncoder
Copy link
Member

Quick question: version affected is listed as 2.17.2 -- but how about 2.18.0.

Or, assuming 2.18.0 affected, would it be possible to test with 2.18.1-SNAPSHOT (of both jackson-databind and jackson-module-kotlin -- from Sonatype OSS Snapshots or locally built from 2.18 branches).
The reason I suggest this is because there have now been multiple small but significant fixes in 2.18 branch wrt any-setters so there is non-trivial chance this might be of one of fixes from:

https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.18.1

and in particular, one of:

@arvgord
Copy link
Author

arvgord commented Oct 15, 2024

Quick question: version affected is listed as 2.17.2 -- but how about 2.18.0.

For version 2.18.0 I created another issue #843 where serialization was broken.

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
@k163377
Copy link
Contributor

k163377 commented Oct 26, 2024

@arvgord
Like comment #843, could you please check if it is possible to reproduce it only with Java?

@arvgord
Copy link
Author

arvgord commented Oct 26, 2024

@k163377, thank you! I was able to fully reproduce the incorrect sorting behavior in Java using your code (test file). I reopened the issue in jackson-databind. I close this issue.

@arvgord arvgord closed this as completed Oct 26, 2024
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
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