As far as I know, the only way to implement parallel class hierarchy on JPA entities is as follows:
@Entity
public abstract class Job<A extends Account> {
@Any(metaColumn = @Column)
@AnyMetaDef(
idType = "integer",
metaType = "string",
metaValues = {
@MetaValue(value = "AccountX", targetEntity = AccountX.class),
@MetaValue(value = "AccountY", targetEntity = AccountY.class)
})
@ManyToOne @JoinColumn
private A account;
public A getAccount() { return account; }
public void setAccount(A account) { this.account = account; }
}
@Entity
public class JobX extends Job<AccountX> {}
@Entity
public class JobY extends Job<AccountY> {}
Where the parallel entities look like:
@Entity
public abstract class Account {}
@Entity
public AcountX extends Account {}
@Entity
public AccountY extends Account {}
This actually works. Objects of type JobX are only associated to objects of type AccountX. The idea behind this kind of design is to be able, in the end, to present two kinds of behaviors depending on the type. Now the problem is that Spring cannot autowire a specific bean provided two implementations. Let's be more specific:
@Component
public class AccountService<A extends Account> {
public A getAccount() { // gets the account }
}
public interface JobService<A extends Account, J extends Job<A>> {
J saveJob(J job);
}
@Component
public class JobServiceX implements JobService<AccountX, JobX> {
@Autowired private AccountService<AccountX> accountService;
@Override
public JobX saveJob(JobX job) { // save implementation for JobX }
}
@Component
public class JobServiceY implements JobService<AccountY, JobY> {
@Autowired private AccountService<AccountY> accountService;
@Override
public JobY saveJob(JobY job) { // save implementation for JobY }
}
Now, if I try to use generics to implement the specific type of bean in order to define behavior:
@Component
public class JobHandler<A extends Account, J extends Job<A>> {
@Autowired private JobService<A,J> jobService;
}
I get the following error: Could not autowire field: private JobService JobHandler.jobService; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [JobService] is defined: expected single matching bean but found 2: jobXService,jobYService
So, I have two questions:
- Is there a workaround? I know that Spring 4 handles generic beans which is the same as annotating
JobService
with@Component
which is clearly wrong since it's an interface and not an implementation. - Regardless of point #1 above, this is starting to create a "generics hell" since now I need to start making all my Spring beans generic. Is there a better design or a better way to do this? Is there any way not to make Job generic and instead provide a getter/setter that can be overwritten in the child entities?
Thank y'all in advance!