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 behavior on deserialization of immutable classes vs records with @JsonIdentityInfo #3307

Open
javster101 opened this issue Oct 24, 2021 · 5 comments
Labels
try-with-later-jackson Indicator that the issue needs to be verified against later version

Comments

@javster101
Copy link

javster101 commented Oct 24, 2021

Describe the bug
When using @JsonIdentityInfo, Jackson deserializes an immutable class fine but the equivalent record does not.

Version information
Jackson 2.13.0

To Reproduce
I have a simple immutable class defined as follows:

@JsonSerialize
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "name", scope = ProjectResource.class)
 public static final class ProjectResource {
        private final String name;
        private final String path;

        @JsonCreator
        public ProjectResource(String name, String path) {
            this.name = name;
            this.path = path;
        }

        public String name() {
            return name;
        }

        public String path() {
            return path;
        }

//equals, hashCode, toString
}

The equivalent record is as follows:

@JsonSerialize
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "name", scope = ProjectResource.class)
public record ProjectResource(String name, String path) {
    @JsonCreator
    public ProjectResource {
    }
}

The XML being deserialized is the following:

<?xml version='1.1' encoding='UTF-8'?>
<project>
   ...
  <resources>
    <resources>
      <name>beevillage.ogg</name>
      <path>resources\1594389476\beevillage.ogg</path>
    </resources>
  </resources>
  ...
</project>

Finally, I have the following mapper (building with -parameters):

var module = new JacksonXmlModule();
module.addDeserializer(Color.class, new ColorDeserializer());

var xmlMapper = new XmlMapper(module);
xmlMapper.registerModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES));
xmlMapper.registerModule(new Jdk8Module());

var builder = xmlMapper.readValue(Files.readAllBytes(projectXml), ProjectBuilder.class);

return builder.build(projectFile, projectXml);

When I deserialize the XML to the first class it works fine, but when I do so to the second class I get the following error:
Can not set final java.lang.String field com.opengg.loader.Project$ProjectResource.name to java.lang.String

Maybe I'm doing something wrong, but my understanding of the record constructor syntax is that it generates the constructor in the same format as the immutable class, including any annotations. If the two classes are identical, I don't see a reason why the deserializer would be unable to use the constructor in the record case but have it work fine in the class case.

EDIT:
This seems to be related to #3297.

@javster101 javster101 added the to-evaluate Issue that has been received but not yet evaluated label Oct 24, 2021
@yihtserns
Copy link
Contributor

What is the purpose of @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "name", scope = ProjectResource.class)?

@cowtowncoder
Copy link
Member

That definitely seems extra without other info.

Also, that @JsonSerialize is unnecessary on class.

Maybe they were copied from some place without fully understanding semantics?

@cowtowncoder
Copy link
Member

@javster101 Although ideally Records and similar POJOs would work same way, due to implementation challenges there are definitely cases where this is not true -- constraints that Records have did/do not exist for POJOs, and as such handling has been created initially for general POJOs and only later trying to make use of & support limitations Records have.

Also: 2.13.0 is old version so please try it out with 2.15.2 -- there have been many recent fixes to Record-type handling in 2.15 (as well as in 2.14).

@cowtowncoder cowtowncoder added try-with-later-jackson Indicator that the issue needs to be verified against later version and removed to-evaluate Issue that has been received but not yet evaluated labels Jun 8, 2023
@yihtserns
Copy link
Contributor

BTW, I asked about the @JsonIdentityInfo because:

  • After removing it from the non-Record class, it still generates the same JSON.
  • After removing it from the Record class, it can deserialize without problem.

@cowtowncoder
Copy link
Member

One other final note: there's reference to XML, so issue may well be related to XML format module.
And there have been TONS of fixes there since version 2.13.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
try-with-later-jackson Indicator that the issue needs to be verified against later version
Projects
None yet
Development

No branches or pull requests

3 participants