@Primary equivalent for autowired Spring JPA repositories

2015-11-03 java spring spring-data spring-data-jpa

I use Spring JPA repositories and entities in an application. Now, in a flavor of that application, I need to extend one of my entities and also provide an extended repository.

For all other beans I need to override/extend I simply create a new implementation and annotate it with @Primary so it will be autowired instead of the default implementation.

For repositories, however, this does not work. I can annotate the new repository with @Primary but it has no effect (both beans are found and can thus not be autowired). This makes sense because the repository is an interface and not an implementation, the implementation is provided by Spring dynamically.

Can I somehow tell Spring (via annotation on the repository or via configuration) which repository to use? Or do I have to do a manual workaround like this Using @Primary in Spring Data JPA repositories or should I come up with a kind of repository provider instead of autowiring?

Edit to make things clearer: Let's say I have an entity A

@Entity
public class A {
  @Id
  private long id;
}

and its repository

public ARepository extends Repository<A, Long> {
}

Now I extend it to the entity B

@Entity
public class B extends A {
}

public interface BRepository extends ARepository {
}

Normally, as per the documentation, you use repositories like this:

@Autowired
private ARepository repository;

This does, however, not work because there are now two beans of the type ARepository. For beans that I implement myself I would use @Primary on the extending class but for repositories there is no implementation of the interface at compile time.

Answers

I would adapt the idea form this answer: https://stackoverflow.com/a/27549198/280244 and this git example https://github.com/netgloo/spring-boot-samples/tree/master/spring-boot-springdatajpa-inheritance/src/main/java/netgloo/models

Introduce a common abstract Repository that is marked with @NoRepositoryBean

@NoRepositoryBean
public interface AbstractARepository<T extends A>
                                    extends Repository<T, Long> {
    T findByName(String name); //or what ever your queries are
}

public ARepository extends AbstractARepository<A> {
   //almost emtpy
}


public BRepository extends AbstractARepository<B> {
   //queries that are special for B
}

Now you can inject ARepository and BRepository, and both are type save!

Just for the record, it is possible to add @Primary support to JPA repositories as suggested here Using @Primary in Spring Data JPA repositories

My implementation of the missing code:

private boolean isSpringDataJpaRepository(Class<?> beanClass) {
      return JpaRepositoryFactoryBean.class.isAssignableFrom(beanClass);
}

I think the answer of @Ralph is better because of the type safety.

Related