Closed Zetten closed 3 months ago
It sounds like what you're trying to do is not achievable through a simple merge patch, as it violates the array handling semantics. That aside, bi-directional relationship are a notoriously known for causing trouble. So unless you can get plain Jackson to produce a merge result, I don't think we're going to introduce more complexity to handle this situation.
Have you tried using actual JSON Patch requests that allow a much more precise definition of what's supposed to be updated in which way? Alternatively, if the state transition is a domain-relevant one, it might be worth introducing a dedicated link relationship for it and manually handle the request.
Thanks for the tips.
I'll spend a few minutes testing Jackson merging - I thought the @JsonManagedReference
and @JsonBackReference
should help there.
Have you tried using actual JSON Patch requests that allow a much more precise definition of what's supposed to be updated in which way?
Yeah, that's been a dead end so far - it seems that patching one property on two levels of nested objects just doesn't resolve correctly (having changed Set collectors
to a List
for index-based access):
[{
"op": "replace",
"path": "outputs/0/collectors/0/replaceContents",
"value": true
}]
Leads to Couldn't find writable property for pointer segment replaceContents on class com.example.demo.entities.TaskOutput in outputs/0/collectors/0/replaceContents
.
Interestingly it does seem to work for the collectors
objects themselves - i.e. I could try to replace outputs/0/collectors/0
entirely - but then I have a backreference issue, as I'm also using @MapsId
to pull an embedded composite ID out of the TaskOutputCollector#taskOutput
property, so I would have to add IDs to my entity responses and rebuild everything just to patch one property!
Alternatively, if the state transition is a domain-relevant one, it might be worth introducing a dedicated link relationship for it and manually handle the request.
But I think this will be the ultimate way forward. It's going to be required for another feature I've got in mind anyway!
Yeah, I'll just continue with my refactoring to a dedicated entity for the relationship - good excuse for it now :smile:
I do wonder if checking for Jackson's @JsonBackReference
could be used as a simple heuristic to escape circular references, as that should only exist in such circumstance. The check could be e.g. in DomainObjectReader#doWitthPersistentProperty (or implemented as a isBackReference()
on something in the PersistentProperty
hierarchy) - but admittedly I don't fully grok how all the Spring Data bits fit together so I'm not sure what the impact/tradeoffs could be!
Following an update to Spring Boot 3.3.1 (Spring Data 2024.0.0 / Spring Data REST 4.3.1 / Spring Data JPA 3.3.1) I'm getting a test failure when trying to PATCH an entity which includes a nested collection of entities which reference the parent.
I've created a minimal reproduction here: https://github.com/Zetten/spring-data-rest-4.3-patch-stackoverflow. It's a somewhat contrived example based on my real entity graph, but roughly: a
TaskConfig
can be used to send the results 'outputs' of some processing task to aBasket
, which is essentially modelled as a link tableTaskOutputCollector
with two ManyToOne relations.Only the
Basket
andTaskConfig
resources are exported via Repository interfaces. My issue occurs when calling PATCH on aTaskConfig
to update itsoutputs
field, i.e. replacing the list of associatedTaskOutput
objects to change a field on one of the nestedTaskOutputCollector
records:In Spring Boot 3.2.7 this works fine. Following the update to Spring Boot 3.31, HTTP PATCH now calls
mergeForPut
, which tries to resolve and merge the relations recursively (TaskOutput -> TaskOutputCollector -> the holding TaskOutput) and therefore errors out with the below StackOverflowError.I believe this is obviously due to the RFC-compliant handling of entities in arrays in merge patches - but the entity graph makes sense, so it seems like the merge should be a bit smarter about detecting recursion.