Skip to content

Object ID handling tries (unnecessarily) to set id value on a Record #4729

Closed

Description

@hjohn

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

When using JsonIdentityInfo on a record, Jackson tries to set the id on the record despite it already being correct. This is odd to say the least, as the correct record is already found, which has the correct id (otherwise it wouldn't be found), and then after that it tries to set the id. Here's the code that's causing the problem in PropertyValueBuffer:

public Object handleIdValue(final DeserializationContext ctxt, Object bean) throws IOException
{
    if (_objectIdReader != null) {
        if (_idValue != null) {
            ReadableObjectId roid = ctxt.findObjectId(_idValue, _objectIdReader.generator, _objectIdReader.resolver);
            roid.bindItem(bean);
            // also: may need to set a property value as well
            SettableBeanProperty idProp = _objectIdReader.idProperty;
            if (idProp != null) {
                return idProp.setAndReturn(bean, _idValue);
            }
        } else {
            // 07-Jun-2016, tatu: Trying to improve error messaging here...
            ctxt.reportUnresolvedObjectId(_objectIdReader, bean);
        }
    }
    return bean;
}

Just before it calls idProp.setAndReturn everything is already correct. The bean variable holds the correct record Device[id=Arris]. The _idValue holds Arris. The idProp is [creator property, name 'id'; inject id 'null']. roId holds [ObjectId: key=Arris, type=com.fasterxml.jackson.databind.deser.impl.PropertyBasedObjectIdGenerator, scope=java.lang.Object].

In other words, it found the correct bean, which already has the correct id, but Jackson wants to still set the id value ... to the same value...

Remvoing the line return idProp.setAndReturn(bean, _idValue); makes the deserialization work correctly.

Version Information

2.18.0

Reproduction

Run below snippet. It will throw an exception:

 No fallback setter/field defined for creator property 'id' (of `org.int4.nexus.core.JacksonBug$Device`) (through reference chain: org.int4.nexus.core.JacksonBug$Configuration["devices"]->java.util.ArrayList[0])
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.List;

public class JacksonBug {

  static String input = """
    {
      "devices": [
        {
          "id": "Arris"
        }
      ],
      "activities": [
        {
          "id": "TV",
          "participants": ["Arris"]
        }
      ]
    }
  """;

  public static void main(String[] args) throws JsonMappingException, JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    Configuration c = mapper.readValue(input, Configuration.class);

  }

  @JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator.class)
  record Device(String id) {}

  record Configuration(List<Device> devices, List<Activity> activities) {}

  record Activity(String id, @JsonIdentityReference(alwaysAsId = true) List<Device> participants) {}
}

Expected behavior

I'd expect this to just work out of the box. It shouldn't be trying to call setters on a record under any circumstances...

Additional context

No response

Activity

  1. added
    to-evaluateIssue that has been received but not yet evaluated
    on Oct 2, 2024
  2. hjohn commented on Oct 2, 2024

    @hjohn
    Author

    I was looking into a better fix for this, and realized that idProp probably should just be null for records. When I use the ObjectIdGenerators.StringIdGenerator (even though I really don't want to generate id's) it does work. Using ObjectIdGenerators.None (which I tried initially) doesn't work either though, as I get a different exception then:

    Cannot construct instance of `org.int4.nexus.core.JacksonBug$Device` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('Arris')
    

    I'm able to proceed though using the StringIdGenerator for now.

    It's unclear to me which of the ObjectIdGenerators should and should not work in combination with records :)

  3. JooHyukKim commented on Oct 3, 2024

    @JooHyukKim
    Member

    Thank you for reporting this.
    There has been some rewrites regarding property introspection in 2.18, but no related change has been made to PropertyValueBuffer since 2021 (according to Git history).

    realized that idProp probably should just be null for records

    And yes, I agree. Seems like it.

  4. added
    RecordIssue related to JDK17 java.lang.Record support
    on Oct 6, 2024
  5. removed
    to-evaluateIssue that has been received but not yet evaluated
    on Feb 10, 2026
  6. cowtowncoder commented on Feb 10, 2026

    @cowtowncoder
    Member

    Quick note: #5238 may have fixed some of this (in 2.20).

    Full verification & complete fix in 3.1.0.

  7. added a commit that references this issue on Feb 10, 2026
    f86d67c
  8. changed the title [-]Object ID handling tries (unnecessarily) to set id value on a record[/-] [+]Object ID handling tries (unnecessarily) to set id value on a Record[/+] on Feb 10, 2026
  9. added this to the 3.1.0 milestone on Feb 10, 2026
  10. added a commit that references this issue on Feb 10, 2026
    be1f763
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    RecordIssue related to JDK17 java.lang.Record supportobjectid

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions