Description
Rafael Renan Pacheco opened DATAREST-1195 and commented
Hi there!
When setting the ANNOTATED property for the repository detection strategy breaks the Resource<MyEntity> param on a @RestController
endpoint. This happens if the @RequestBody
payload has a foreign key reference, which should be referenced as an URL. The exception message is the following:
"JSON parse error: Can not construct instance of com.myproject.entity.ParentEntity: no String-argument constructor/factory method to deserialize from String value ('parent/3');
nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.myproject.entity.ParentEntity:
no String-argument constructor/factory method to deserialize from String value ('parent/3')\n
at [Source: java.io.PushbackInputStream@12de10ef; line: 6, column: 1] (through reference chain: com.myproject.entity.ParentEntity[\"parentEntity\"])"
If I unset the detection strategy to use it's default value, the issue is gone and Spring Data Rest is able to find the parent entity just fine.
Here is some snippets to better understand the current situation:
This is the JSON that is POSTed to the /users endpoint to create some user. Note that the foreign key profile is referenced by a URL, since we are using HATEOAS:
{
"profile": "profiles/1",
"name": "Some User",
"username": "some@email.com",
"password": "password"
}
This is the UserRepository:
public interface UserRepository extends JpaRepository<User, Integer> {
}
This is the UserController (the ProfileController and CRUD endpoints also exists):
@RestController
@RequestMapping("/users")
public class UserController {
private UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping("")
public ResponseEntity<PagedResources<UserResource>> all(Pageable page,
PagedResourcesAssembler<User> assembler) {
// find all and return, working fine
}
@GetMapping("{id}")
public ResponseEntity<UserResource> get(@PathVariable Integer id) {
// fine one and return, working fine
}
// Here the Resource<User> breaks if ANNOTATED strategy is used.
@PostMapping("")
public ResponseEntity<Void> create(@RequestBody Resource<User> userResource) {
User user = userResource.getContent();
userRepository.save(user);
// and return with some location header
}
@PatchMapping("{id}")
public ResponseEntity<Void> update(@RequestBody Resource<User> userResource, @PathVariable Integer id) {
// same issue here because of Resource<>
}
@DeleteMapping("{id}")
public ResponseEntity<Void> delete(@PathVariable Integer id) {
// delete one, working fine
}
}
In this project I need all my endpoints to be @RestController
, and I can't have any endpoint generated by the JPA Repositories. I need @RestController
to create custom endpoints beyond the CRUD ones, and also to write business logic on the CRUD endpoints. For now I have to be very careful when creating an JPA Repository, because I'm using the default detection strategy, which exposes lots of JPA Repositories endpoints that are not shadowed by a full CRUD from a @RestRepository
.
Question: Is disabling Resource URL references expected when using ANNOTATED strategy, or could this be a bug?
Extra question: The documentation lists an ANNOTATION option for the detection strategy, but this enum doesn't exist. Just ANNOTATED works for now.
Dependencies:
[INFO] +- org.springframework.boot:spring-boot-starter-data-rest:jar:1.5.10.RELEASE:compile
[INFO] | \- org.springframework.data:spring-data-rest-webmvc:jar:2.6.10.RELEASE:compile
[INFO] | \- org.springframework.data:spring-data-rest-core:jar:2.6.10.RELEASE:compile
Affects: 2.6.10 (Ingalls SR10)