The main entity Movie
has a OneToMany
relation to Ratings
. Ratings
has a composite primary key with movieID
and ratingPlatformId
. Only the Movie
entity has a REST repository, and IDs are exposed. A single movie API exists where GET works fine, but updating via PUT doesn't. Updating the ratings list gives unexpected results. For example:
Before:
{
"id": 2,
"name": "The Dark Knight",
"ratings": [
{
"ratingPlatformId": 1,
"score": 10
}
]
}
PUT Request:
{
"id": 2,
"name": "The Dark Knight",
"ratings": [
{
"ratingPlatformId": 2,
"score": 2
}
]
}
Expectation: The rating for ratingPlatformId 1 should be deleted, and a new one with ratingPlatformId 2 should be created.
Actual Result:
{
"id": 2,
"name": "The Dark Knight",
"ratings": [
{
"ratingPlatformId": 1,
"score": 2
}
]
}
I debugged a bit and ratingPlatformId is not considered at all during the PUT operation and gets skipped here as it is an ID.
The only working setup is inspired by AresEkb from this issue and involves:
-
Using a
HashMap
for theOneToMany
ratings and writinggetRatings
andsetRatings
methods manually. -
Adding some AOP magic for
RepositoryEntityController.putItemResource
to set the movie in the ratings.
- main: Working "solution" with
HashMap
and AOP workarounds. - experimental/hash-set: Setup with
HashSet
and AOP, but adding list elements in the middle fails. - experimental/plain: Setup with
HashSet
and without any AOP or workarounds; many tests fail.
-
Clone the repository:
git clone https://github.com/t0bij/springdatarest-put-reproducer.git cd springdatarest-put-reproducer
-
Build the project:
mvn clean install
-
Run the application:
mvn spring-boot:run
-
Open the Swagger UI to interact with the API: Swagger UI
Run the tests with:
mvn test
This test verifies that a movie with ID 1 can be retrieved correctly.
This test verifies that updating the title of a movie works as expected.
This test checks if changing the order of ratings in the request body is handled correctly and ensures that the order in the request body does not matter.
This test ensures that all ratings of a movie can be deleted successfully.
This test verifies the replacement of a rating. So deleting a raing for one platform and adding a new one for another platform in the same put request.
This test verifies the insertion of new ratings for an existing movie.
This test adds multiple ratings and one in the middle. Initially, there is a rating for ratingPlatformId 1
. Then a rating for ratingPlatformId 3
is added. Finally, a rating for ratingPlatformId 2
is added, which is in the middle.