spring-projects / spring-projects/spring-data-rest
Failure to link persistent entities to a target entity's member variable if member variable is of abstract type [DATAREST-214]
@odrotbohm is already working on this.
Since Dec 31, 2020.
- Dominant language
- Java
- Stars
- 958
- Forks
- 568
- PR merge metrics
- No merged PRs in 30d
Description
Aaron Loes opened DATAREST-214 and commented
This is in relation to DATAREST-202.
When attempting to link an entity to the value of another entity, the code is attempting to look up the repository for the linked entity by using the target entities member variable type. This causes issues if the member variable type is an abstract class. Instead the code should look up the repository information of the linked entities via the URL that it is passed and then validate that the type is allowed to be assigned.
Pseudo Example:
Given a Domain Model:
class Farm {
@DBRef
List<? extends Animal> animals;
}
abstract class Animal { /*...*/ }
class Horse extends Animal { /*...*/ } // this has a repository
class Cow extends Animal { /*...*/ } // this has a repository
class Pig extends Animal { /*...*/ } // this has a repository
And given a request
PUT /myApp/farm/1234/animals HTTP/1.1
Host: localhost:8080
Content-Length: 96
Content-Type: text/uri-list; charset=UTF-8
Accept: application/json; charset=utf-8
Origin: http://localhost:8080
http://localhost:8080/myApp/horse/6543
http://localhost:8080/myApp/pig/7654
http://localhost:8080/myApp/cow/9457
The code is currently looking for a Repository that handles the "Animal" class. Instead, when going to assign the values to Farm#animals, it should use the URL's given to find the appropriate repository and verify that their types are a subtype of Animal.
I have currently KLUDGED together a fix which meant replacing the RepositoryPropertyReferenceController and modifying its loadPropertyValue method like so:
private Object loadPropertyValue(Class<?> type, String href) {
String id = href.substring(href.lastIndexOf('/') + 1);
// get url for linked entity
String repositoryUrl = href.substring(0, href.lastIndexOf('/'));
// get repository name for linked entity
String repositoryName = repositoryUrl.substring(repositoryUrl.lastIndexOf('/') + 1);
// look up resource metadata for linked entity
ResourceMetadata metadata = null;
for (Class<?> domainType : repositories) {
ResourceMetadata mapping = mappings.getMappingFor(domainType);
if (mapping.getPath().matches(repositoryName) && mapping.isExported()) {
metadata = mapping;
break;
}
}
// get type from linked entity if none found, otherwise use default
if (metadata != null) {
type = metadata.getDomainType();
}
return converter.convert(id, STRING_TYPE, TypeDescriptor.valueOf(type));
}
Affects: 2.0 M1 (Codd)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.