Follow-up to #1496.
#1496 enabled Object Ids with Builder-based deserialization for the common cases and added clear error reporting (InvalidDefinitionException) for forward Object Id references bound to scalar properties, where the reference would otherwise be silently resolved against the discarded Builder instance.
One case remains broken: forward Object Id references that appear as items of a Collection-typed property. The collection-item path does not go through ObjectIdReferenceProperty.deserializeSetAndReturn, so DeserializationContext.addPendingForwardRef is never called and the guard in BuilderBasedDeserializer.finishBuild (hasPendingForwardRefsFor) does not trip. As a result:
- No error is reported.
- The unresolved slot ends up holding the
Builder instance instead of the built target object after resolution.
Reproduction
See src/test/java/tools/jackson/databind/tofix/ObjectIdWithBuilder1496Test.java (forwardReferenceInCollection, currently @JacksonTestFailureExpected):
{"entities":[
{"id":1,"refs":[2]},
{"id":2,"ref":1,"refs":[]}
]}
Entity uses @JsonIdentityInfo + @JsonDeserialize(builder = EntityBuilder.class). After deserialization, entities[0].refs[0] is an EntityBuilder rather than the built Entity with id 2.
expected: Entity@... but was: EntityBuilder@...
Suggested fix direction
Two options, both requiring changes beyond the scope of #1496:
- Plumb collection-item forward references through
addPendingForwardRef so the existing BuilderBasedDeserializer.finishBuild guard catches them and emits the same InvalidDefinitionException ("Cannot resolve forward Object Id references for Builder-based type …").
- Actually support the case: re-bind collection-item references from the builder to the built object when
updateObjectId is called in finishBuild. This would likely require the collection Referring implementation to late-bind via the ReadableObjectId entry after updateObjectId rewrites the bound item.
Option 1 matches the existing fail-fast contract for the scalar case and is the minimum acceptable fix. Option 2 is the full solution.
Version
3.x (observed on current 3.x branch after #1496 / commit 476f3d9f5).
Follow-up to #1496.
#1496 enabled Object Ids with Builder-based deserialization for the common cases and added clear error reporting (
InvalidDefinitionException) for forward Object Id references bound to scalar properties, where the reference would otherwise be silently resolved against the discardedBuilderinstance.One case remains broken: forward Object Id references that appear as items of a
Collection-typed property. The collection-item path does not go throughObjectIdReferenceProperty.deserializeSetAndReturn, soDeserializationContext.addPendingForwardRefis never called and the guard inBuilderBasedDeserializer.finishBuild(hasPendingForwardRefsFor) does not trip. As a result:Builderinstance instead of the built target object after resolution.Reproduction
See
src/test/java/tools/jackson/databind/tofix/ObjectIdWithBuilder1496Test.java(forwardReferenceInCollection, currently@JacksonTestFailureExpected):{"entities":[ {"id":1,"refs":[2]}, {"id":2,"ref":1,"refs":[]} ]}Entityuses@JsonIdentityInfo+@JsonDeserialize(builder = EntityBuilder.class). After deserialization,entities[0].refs[0]is anEntityBuilderrather than the builtEntitywith id 2.Suggested fix direction
Two options, both requiring changes beyond the scope of #1496:
addPendingForwardRefso the existingBuilderBasedDeserializer.finishBuildguard catches them and emits the sameInvalidDefinitionException("Cannot resolve forward Object Id references for Builder-based type …").updateObjectIdis called infinishBuild. This would likely require the collectionReferringimplementation to late-bind via theReadableObjectIdentry afterupdateObjectIdrewrites the bound item.Option 1 matches the existing fail-fast contract for the scalar case and is the minimum acceptable fix. Option 2 is the full solution.
Version
3.x (observed on current
3.xbranch after #1496 / commit476f3d9f5).