Reputation: 4057
Suppose I have two resources Person
and Article
@Entity
@Table(name = "person")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long person_id;
private String firstName;
private String lastName;
@OneToMany(mappedBy="person", cascade=CascadeType.ALL)
private List<Article> articles = new ArrayList<>();
}
@Entity
@Table(name="article")
public class Article {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String title;
private String details;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="person_id")
private Person person;
}
I now want to add HATEOAS support to the response of the controller for which I am using org.springframework.hateoas.ResourceAssembler
public class PersonResourceAssembler implements ResourceAssembler<Person, Resource<Person>> {
private EntityLinks entityLinks;
public UserJobResourceAssembler(EntityLinks entityLinks) {
this.entityLinks = entityLinks;
}
@Override
public Resource<Person> toResource(Person entity) {
Resource<UserJob> resource = new Resource<>(entity);
resource.add(
entityLinks.linkFor(Person.class).withSelfRel()),
entityLinks.linkFor(...logic...).withRel("articles")) //here I am hardcoding the relation link name i.e "article"
);
return resource;
}
}
So, in above code the "article" is hardcoded for the link name, but I don't want to do it this way. I want it do in the way Spring-Data-REST
handles it i.e for every relationship it auto detects the name of the variable used inside the Entity
class e.g articles
will be picked from Person
and person
will be picked from Article
.
I have no idea how Spring-Data-REST
handles it, but are there any readymade/custom solutions for this requirement?
Upvotes: 0
Views: 97
Reputation: 23246
You can use the reflection API to introspect the entity and find associations. Something like:
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.persistence.OneToMany;
public class AssociationUtility {
public static List<Field> getAssociatedFields(Object entity) {
Stream<Field> fields = Arrays.stream(entity.getClass().getDeclaredFields());
return fields.filter(field -> field.getAnnotation(OneToMany.class)
!= null).collect(Collectors.toList());
}
public static void main(String[] args) {
List<Field> fields = getAssociatedFields(new Customer());
fields.stream().forEach(f -> System.out.println("Make a link for Class: "
+ ((ParameterizedType) f.getGenericType()).getActualTypeArguments()[0]
+ " with rel: " + f.getName()));
System.exit(0);
}
}
Upvotes: 1