Yes it's possible to implement these classes using TABLE_PER_CLASS
strategy with generics, but you have to use @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
annotation instead of @MappedSuperClass
.
To know more about TABLE_PER_CLASS
strategy visit jpa advanced mappings
To prepare your abstract classes using generics all you have to do is understand the relation between classes before using generics. After that you have to understand recursive generics
concept to implement your case using generics.
For more information's visit introduction to generics
Here is the implementation of classes:-
Institution class
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Institution<T extends Institution<T, S>, S extends Animal<S, T>> {
@Id
@GeneratedValue
private int id;
//add properties, constructors and methods
@OneToMany(targetEntity = Animal.class, mappedBy = "institution", cascade = CascadeType.ALL)
private List<S> animals;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<S> getAnimals() {
return animals;
}
public void setAnimals(List<S> animals) {
this.animals = animals;
}
}
Animal class
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Animal<T extends Animal<T, S>, S extends Institution<S, T>> {
@Id
@GeneratedValue
private int id;
//add properties, constructors and methods
@ManyToOne(targetEntity = Institution.class, cascade = CascadeType.ALL)
private S institution;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public S getInstitution() {
return institution;
}
public void setInstitution(S institution) {
this.institution = institution;
}
}
Important Note:- During implementing the entities using generics you must specify the targetEntity
class in @OneToOne
, @OneToMany
, @ManyToOne
and @ManyToMany
annotations as shown in the above code because JPA cannot detect the target entity in generics.
Zoo and ZooAnimal classes
@Entity
public class Zoo extends Institution<Zoo, ZooAnimal> {
//add properties, constructors and methods
}
@Entity
public class ZooAnimal extends Animal<ZooAnimal, Zoo> {
//add properties, constructors and methods
}
Circus And CircusAnimal
@Entity
public class Circus extends Institution<Circus, CircusAnimal> {
//add properties, constructors and methods
}
@Entity
public class CircusAnimal extends Animal<CircusAnimal, Circus> {
//add properties, constructors and methods
}
As you can see in the implementation of subclasses, there is no need to override getAnimals()
and getInstitution()
methods to change their return types because we already specified its return types using generics.