Skip to content

Allow updates from the owner side of ManyToOne/ManyToMany relationships - #2608

Open
ruthst00 wants to merge 2 commits into
spring-projects:mainfrom
ruthst00:issue/1810
Open

ruthst00 wants to merge 2 commits into
spring-projects:mainfrom
ruthst00:issue/1810

Conversation

@ruthst00

Copy link
Copy Markdown

Fixes #1810

The issue GH-1810 still existed in SDR 5.0.7 (and the current 5.2.0-1810-SNAPSHOT branch). The bug: when a client sends a PUT/POST/PATCH/DELETE to the inverse (mappedBy) side of a JPA bidirectional association (e.g. PUT /authors/{id}/books where Author.books has @ManyToMany(mappedBy="authors")), SDR would return HTTP 204 implying success — but JPA silently ignores writes on the non-owning side, so no database changes were made.

The fix (commit d7ffd2ce) adds two new files and modifies two existing ones:

  1. InverseSideAssociationDetector (new) — uses ClassUtils.forName + reflection to detect a non-empty mappedBy attribute on @OneToMany, @ManyToMany, or @OneToOne annotations. Gracefully returns false when jakarta.persistence is absent from the classpath.

  2. RepositoryPropertyReferenceControllerdoWithReferencedProperty now calls InverseSideAssociationDetector.isInverseSide() before any write operation. If the property is the inverse side, it throws HttpRequestMethodNotSupportedException which the existing @ExceptionHandler converts to HTTP 405 Method Not Allowed with Allow: GET and a descriptive message directing the caller to update the owning side instead. GET requests are unaffected.

  3. InverseSideAssociationDetectorUnitTests (new) — 6 unit tests covering all three annotation types with/without mappedBy.

  4. RepositoryPropertyReferenceControllerIntegrationTests — 4 new JPA integration tests verifying PUT/POST on the inverse side throw the exception, GET still works, and PUT on the owning side continues to work normally. All 15 tests (9 unit + 6 integration) pass.

  • You have read the Spring Data contribution guidelines.
  • You use the code formatters provided here and have them applied to your changes. Don’t submit any formatting related changes.
  • You submit test cases (unit or integration tests) that back your changes.
  • You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).

ruthst00 and others added 2 commits September 13, 2026 15:07
Signed-off-by: ruthes00 <ruthes00@gmail.com>
…P 405

Fixes spring-projectsGH-1810

When a JPA entity exposes a bidirectional association via Spring Data REST,
the inverse (non-owning) side is annotated with mappedBy on @onetomany,
@manytomany, or @OnetoOne. JPA only persists association changes from the
owning side; writes on the inverse side are silently ignored by the JPA
provider even though the entity is saved. This caused SDR to return HTTP 204
(No Content) implying success while making no actual database changes.

This commit introduces InverseSideAssociationDetector, which uses reflection
to inspect JPA annotations on a PersistentProperty and detect a non-empty
mappedBy attribute. The detection is performed via ClassUtils.forName so
that the class degrades gracefully when jakarta.persistence is absent from
the classpath (it is an optional dependency of the webmvc module).

RepositoryPropertyReferenceController.doWithReferencedProperty now calls
this detector before executing any write operation (PUT, POST, PATCH,
DELETE). If the property is the inverse side of a JPA association, the
request is rejected with HTTP 405 Method Not Allowed and an Allow: GET
header, along with a descriptive message directing the caller to update
the owning side instead.

GET requests on inverse-side associations are unaffected and continue to
work normally.

Tests added:
- InverseSideAssociationDetectorUnitTests: 6 unit tests covering all
  three annotation types (@onetomany, @manytomany, @OnetoOne) with and
  without mappedBy, plus @manytoone (always owning side).
- RepositoryPropertyReferenceControllerIntegrationTests: 4 new JPA
  integration tests verifying that PUT/POST on the inverse side throw
  HttpRequestMethodNotSupportedException, GET on the inverse side returns
  HTTP 200, and PUT on the owning side continues to work normally.

Signed-off-by: ruthes00 <ruthes00@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

How come Spring Data Rest only allows updates from the owner side of ManyToOne/ManyToMany? [DATAREST-1449]

2 participants