I have Spring Data REST based application with repository
public interface CriterionRepository extends JpaRepository<Criterion, Long> {
}
whereas Criterion
is base class:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Criterion extends AbstractEntity {}
and NameCriterion
is its subclass
@Entity
public class NameCriterion extends Criterion {
private final String name;
}
Spring Data REST exports the repository as REST resource and one can access it at http://localhost:8080/api/criteria/
Exported resource looks as follows:
{
"_embedded": {
"nameCriteria": [{
"_links": {
"self": {
"href": "http://localhost:8080/api/nameCriterion/1"
},
"nameCriterion": {
"href": "http://localhost:8080/api/nameCriterion/1"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/api/criteria"
},
"profile": {
"href": "http://localhost:8080/api/profile/criteria"
}
},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
When I try to follow self link, there is no mapping for http://localhost:8080/api/nameCriterion/1
I can follow http://localhost:8080/api/criteria/1 though and I get response without name field from NameCriterion
{
"_links": {
"self": {
"href": "http://localhost:8080/api/nameCriterion/1"
},
"nameCriterion": {
"href": "http://localhost:8080/api/nameCriterion/1"
}
}
}
My assumption is it is a problem with Jackson mapper defined in REST exporter which is not tweaked correctly to handle abstract class Criterion
used in JpaRepository
as aggregate root.
What Jackson customization should I apply to make it working properly?
In other words, what Jackson module should I create?
There is no need to create a Jackson module. To use a single table for inherited entities we can use @RestResource annotation to mark them as the same resources:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "criteria")
public abstract class Criterion extends AbstractEntity {
}
@RestResource(rel = "criteria", path = "criteria")
@Entity
public class NameCriterion extends Criterion {
private String name;
}
@RestResource(rel = "criteria", path = "criteria")
@Entity
public class TitleCriterion extends Criterion {
private String title;
}
@RepositoryRestResource(path = "criteria", collectionResourceRel = "criteria", itemResourceRel = "criterion")
public interface CriterionRepository extends JpaRepository<Criterion, Long> {
}
So it becomes possible to obtain all the resources (NameCriterion and TitleCriterion) in one output:
GET http://localhost:8080/api/criteria
{
"_embedded": {
"criteria": [
{
"name": "name1",
"_links": {
"self": {
"href": "http://localhost:8080/api/criteria/1"
},
"nameCriterion": {
"href": "http://localhost:8080/api/criteria/1"
}
}
},
{
"title": "title1",
"_links": {
"self": {
"href": "http://localhost:8080/api/criteria/2"
},
"titleCriterion": {
"href": "http://localhost:8080/api/criteria/2"
}
}
}
]
}
}
GET http://localhost:8080/api/criteria/1
{
"name": "name1",
"_links": {
"self": {
"href": "http://localhost:8080/api/criteria/1"
},
"nameCriterion": {
"href": "http://localhost:8080/api/criteria/1"
}
}
}
GET http://localhost:8080/api/criteria/2
{
"title": "title1",
"_links": {
"self": {
"href": "http://localhost:8080/api/criteria/2"
},
"titleCriterion": {
"href": "http://localhost:8080/api/criteria/2"
}
}
}
Working example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With