spring-projects / spring-projects/spring-data-rest
Polymorphic projections for associations [DATAREST-783]
@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
Mikhail Kadan opened DATAREST-783 and commented
Consider the following case:
A Book has multiple authors, each of them may be either a Professional or an Amateur, e.g.:
class Book { String title; @OneToMany Set<Author> authors; }
class Person { String name; int age; }
class Author extends Person { @ManyToOne Book book; String licenseId; }
class AmateurAuthor extends Author { String favoriteColor; }
class ProfessionalAuthor extends Author { int professionalExperience; }
Corresponding repositories:
interface BookRepository {}
interface AmateurAuthorRepository {}
interface ProfessionalAuthorRepository {}
And the following projections:
@Projection(name = "default", types = Book.class)
public interface BookProjection { String getTitle(); Set<AuthorProjection> getAuthors(); }
public interface PersonProjection { String getName(); }
public interface AuthorProjection extends PersonProjection { String getLicenseId(); }
@Projection(name = "default", types = AmateurAuthor.class)
interface AmateurAuthorProjection extends AuthorProjection { String getFavoriteColor(); }
@Projection(name = "default", types = ProfessionalAuthor.class)
public interface ProfessionalAuthorProjection extends AuthorProjection { int getProfessionalExperience(); }
What do we have there is a Book having a set of Authors, each of them may be either an AmateurAuthor or a Professional Author.
What do I expect to get when I ask for a book resource/collection with a "default" projection:
... {
"title": "Book #1",
"authors": {
"_embedded": {
"professionals": [{"name": "Name #1", "licenseId": "License #1", professionalExperience": 10, "_links": {...}}, ...]
"amateurs": [{"name": "Name #2", "licenseId": "License #2", "favoriteColor": "pink", "_links": {...}}, ...]
}
}
} ...
But that's what I actually get:
... {
"title": "Book #1",
"authors": [
{"name": "Name #1", "licenseId": "License #1", "_links": {...}}, ...
{"name": "Name #2", "licenseId": "License #2", "_links": {...}}, ...
}]
} ...
As you see, I have no info on the type of an author and I don't get any additional properties defined for their polymorphic projections. That means only the base projection (AuthorProjection), and not inherited projections (AmateurAuthorProjection, ProfessionalAuthorProjection) is considered when constructing the response.
That could be future proved by defining:
@Projection(name = "default2", types = Book.class)
public interface BookProjection2 { String getTitle(); Set<PersonProjection> getAuthors(); }
And then requesting the "default2" provides:
... {
"title": "Book #1",
"authors": [
{"name": "Name #1", "_links": {...}}, ...
{"name": "Name #2", "_links": {...}}, ...
}]
} ...
Another approach I tried was:
@Projection(name = "default3", types = Book.class)
public interface BookProjection3 { String getTitle(); Set<Author> getAuthors(); }
But that way I get no projection for "authors" at all:
... {
"title": "Book #1",
"authors": [
{"name": "Name #1", "age": 10, "licenseId": "License #1", "professionalExperience": 10}, ...
{"name": "Name #2", "age": 10, "licenseId": "License #1", "favoriteColor": "pink"}, ...
}]
} ...
As for me this relates somehow to the https://jira.spring.io/browse/DATAREST-464
I have also included a sample project to demonstrate this issue
Affects: 2.4.2 (Gosling SR2)
Attachments:
- spring-data-rest-polymorphic-projections.zip (289.73 kB)
1 votes, 1 watchers
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.