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

Inconsistent serialization with @JsonUnwrapped annotation using shared vs. new ObjectMapper instances #4697

Closed
1 task done
SandeepGaur2016 opened this issue Sep 13, 2024 · 4 comments
Labels
duplicate Duplicate of an existing (usually earlier) issue has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue

Comments

@SandeepGaur2016
Copy link
Contributor

SandeepGaur2016 commented Sep 13, 2024

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

I am using Jackson version 2.16.1 and have encountered a peculiar behavior. According to the API documentation, it is recommended to use a common ObjectMapper instance. However, I observe different serialization results when using a shared instance versus a new instance. I have reproduced this issue with a simple example.

public class First {
  @JsonUnwrapped(prefix = "")
  final Thrid thrid = new Thrid();
}
public class Second {
  @JsonUnwrapped(prefix = "fromSecond")
  final Thrid thrid = new Thrid();
}
public class Thrid {
  @JsonUnwrapped(prefix = "fromThird")
  final Common common = new Common("1", "2");
}

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Common {

  public String getA() {
    return a;
  }

  public String getB() {
    return b;
  }

  String a;
  String b;

  public Common() {

  }
  public Common(String a, String b) {
    this.a = a;
    this.b = b;
  }
}

public static void main(String[] args) throws JsonProcessingException {
    First first = new First();
    Second second = new Second();
    ObjectMapper objectMapper = new ObjectMapper();
    System.out.println(objectMapper.writeValueAsString(first));
    System.out.println(objectMapper.writeValueAsString(second));
    System.out.println(new ObjectMapper().writeValueAsString(second));
  }

Output--

{"fromThirda":"1","fromThirdb":"2"}
{"fromThirda":"1","fromThirdb":"2"}
{"fromSecondfromThirda":"1","fromSecondfromThirdb":"2"}`

The output of the last two lines should be the same, but this is not the case. It appears that the @JsonUnwrapped annotation’s previous value for the Third class is being cached somewhere.
public class First { @JsonUnwrapped(prefix = "") final Thrid thrid = new Thrid(); }

If I use a non-empty string instead of an empty one in the above class, the results are consistent. Can someone please help us with this?

Version Information

2.14.2, 2.16.1, 2.17.2

Reproduction

<-- Any of the following

  1. Brief code sample/snippet: include here in preformatted/code section
  2. Longer example stored somewhere else (diff repo, snippet), add a link
  3. Textual explanation: include here
    -->
public class First {
  @JsonUnwrapped(prefix = "")
  final Thrid thrid = new Thrid();
}
public class Second {
  @JsonUnwrapped(prefix = "fromSecond")
  final Thrid thrid = new Thrid();
}
public class Thrid {
  @JsonUnwrapped(prefix = "fromThird")
  final Common common = new Common("1", "2");
}

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Common {

  public String getA() {
    return a;
  }

  public String getB() {
    return b;
  }

  String a;
  String b;

  public Common() {

  }
  public Common(String a, String b) {
    this.a = a;
    this.b = b;
  }
}

public static void main(String[] args) throws JsonProcessingException {
    First first = new First();
    Second second = new Second();
    ObjectMapper objectMapper = new ObjectMapper();
    System.out.println(objectMapper.writeValueAsString(first));
    System.out.println(objectMapper.writeValueAsString(second));
    System.out.println(new ObjectMapper().writeValueAsString(second));
  }

Expected behavior

Object mapper shared object should behave same as new instance as there is no configuration involved

Additional context

No response

@SandeepGaur2016 SandeepGaur2016 added the to-evaluate Issue that has been received but not yet evaluated label Sep 13, 2024
@cowtowncoder cowtowncoder added the has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue label Sep 13, 2024
@JooHyukKim
Copy link
Member

Right, seems like sort of caching is affecting this behavior.

As an immediate solution, how about serializing all instances in intended order as warm-up?

Also, try to look for pre-existing issue. I think I saw similar Github issue

@cowtowncoder
Copy link
Member

Yes, this definitely looks like a bug, possibly related to caching of serializers (or resolution via ResolvableSerializer). There is at least one failing test (and issue) but the one I recall was failing in different way I think (StackOverflow maybe).

@cowtowncoder cowtowncoder removed the to-evaluate Issue that has been received but not yet evaluated label Sep 21, 2024
cowtowncoder pushed a commit that referenced this issue Sep 21, 2024
@SandeepGaur2016
Copy link
Contributor Author

Hi @cowtowncoder @JooHyukKim , I have pushed a fix for it, can you please review,
#4722

Thanks,
Sandeep gaur

@cowtowncoder cowtowncoder changed the title Inconsistent Serialization with Jackson’s @JsonUnwrapped Annotation Using Shared vs. New ObjectMapper Instances Inconsistent serialization with @JsonUnwrapped annotation using shared vs. new ObjectMapper instances Oct 1, 2024
@cowtowncoder cowtowncoder added the duplicate Duplicate of an existing (usually earlier) issue label Oct 3, 2024
@cowtowncoder
Copy link
Member

Actually, I'm pretty sure this is dup of #2461 so will close as such, keep earlier one. Fixed by same PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate Duplicate of an existing (usually earlier) issue has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue
Projects
None yet
Development

No branches or pull requests

3 participants