0

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:

  1. 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.
  2. 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!

Poly
  • 195
  • 2
  • 8
  • Are you sure this is working as you think it is (at the Entity level)? I have never seen any documentation saying such constructs are supported. – Alan Hay Mar 13 '15 at 17:34
  • @alan-hay Sorry, I was trying to be less verbose. I'm use `@Any` and `@AnyMetaDef` from Hibernate as shown [here](https://github.com/zzantozz/testbed/tree/master/hibernate-any). This seems to work. I edited my question with the correct annotations. – Poly Mar 13 '15 at 18:01

0 Answers0