Spring Data - How to reuse repository in repository fragment?

Update: the following is using Spring Boot 2.1.0

I have a Spring Data repository and I am trying to provide some custom functionality to it, following the fragments example from the documentation.

So I've added an extra interface to the repository:

public interface UserRepository extends JpaRepository<User, Long>, UserExtraLogic {
    User findByFirstNameAndLastName(String firstName, String lastName);
}

with this custom interface:

interface UserExtraLogic {
    void ensureHasAccess();
}

and its implementation:

class UserExtraLogicImpl implements UserExtraLogic {
    public void ensureHasAccess() {
    }
}

The problem is that I would like to be able to use my repositories inside UserExtraLogicImpl, so that I can reuse query methods like findByFirstNameAndLastName without having to write them by myself with EntityManager. So I tried this:

class UserExrtaLogicImpl implements UserExtraLogic {
    @Autowired
    private UserRepository userRepository;
}

But then the application does not start. I get a NullPointerException, but I think it's just Spring getting into a cycle trying to resolve these dependencies.

Is what I'm trying to do possible? Is there another way to do this?

You can lazily load your repository with ObjectFactory<T> (Spring concept) or Provider<T> (standard java api).

class UserExrtaLogicImpl implements UserExtraLogic {
    @Autowired
    private ObjectFactory<UserRepository> userRepository;

    public void soSomething() {
         userRepository().getObject().findById(xxx);
    }
}

Spring Data Commons, Spring Data repositories are implemented by using fragments that Fragments are the base repository, functional aspects letting you reuse customizations across different repositories. Value object representing a repository fragment. Repository fragments are individual parts that contribute method signatures. They are used to form a RepositoryComposition. Fragments can be purely structural or backed with an implementation. Structural fragments are not backed by an implementation and are primarily used to discover the

I have the exactly the same code patterns and encounter the same problem in a recent project and I finally solve it by using @Lazy to lazy initialise UserRepository :

class UserExrtaLogicImpl implements UserExtraLogic {

    @Lazy
    @Autowired
    private UserRepository userRepository;

}

Spring Data JPA, Spring Data repositories are implemented by using fragments that Fragments are the base repository, functional aspects letting you reuse customizations across different repositories. the new RepositoryComposition.RepositoryFragments containing all existing fragments and the given RepositoryComposition.RepositoryFragments as last elements. iterator public Iterator<RepositoryFragment<?>> iterator() Specified by: iterator in interface Iterable<RepositoryFragment<?>> methods public Stream<Method> methods() Returns: Stream of

Repositories enablement

From documentation

If you're using Spring XML configuration, you should have this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jpa="http://www.springframework.org/schema/data/jpa"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/jpa
    http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

  <jpa:repositories base-package="com.acme.repositories" />

</beans>

If you're using Java configuration instead, you should have this:

@Configuration
@EnableJpaRepositories("com.acme.repositories")
class ApplicationConfiguration {

  @Bean
  EntityManagerFactory entityManagerFactory() {
    // …
  }
}
Repositories configuration

Also, you need to add @Repository annotation on your repositories:

@Repository
public interface UserRepository extends JpaRepository<User, Long>, UserExtraLogic {
    User findByFirstNameAndLastName(String firstName, String lastName);
}

Explanation

From documentation

Using the repositories element looks up Spring Data repositories as described in "Creating Repository Instances". Beyond that, it activates persistence exception translation for all beans annotated with @Repository, to let exceptions being thrown by the JPA persistence providers be converted into Spring’s DataAccessException hierarchy.

Spring Data JPA Tutorial: Adding Custom Methods to All Repositories, Creating a Base Repository Interface. When we want to add custom methods into all Spring Data JPA repositories, the first thing that we have to is  Fragment configuration consisting of an interface name and the implementation class name.

Pay attention to this in documentation.

Extending the fragment interface with your repository interface combines the CRUD and custom functionality and makes it available to clients.

When you extend your fragment interface, your final repository will include that as well. That is the benift of it. If you want to access original repository logic I can suggest you 3 methods.

  1. Add your query in your fragment and extend it in your repository. Then in your service method include an aggregated method. In that method write your logic.
  2. In your custom interface, inlude your repository and do not extend your custom interface in repository.
  3. Use a decorator class. Delegate all the methods to repository and combine custom logic with repository.

Do not include circular dependencies as it is not a good practise.

Custom Implementations For Spring Data Repositories, Spring Data repositories are implemented by using fragments that form a repository Multiple repositories may use a fragment interface, letting you reuse​  In this tutorial i am going to explain how to use query methods and custom repository implementation in Spring Data JPA framework. I have used Primfaces and JSF to develop the front end to access data using Spring Data infrastructure. When you’re developing a Spring Data Repository, you’ll have three options:

Spring Data Composable Repositories, Learn how to use multiple fragments to implement a Spring Data repository. Interface containing the configurable options for the Spring Data repository subsystem. RepositoryConfigurationUtils Helper class to centralize common functionality that needs to be used in various places of the configuration implementation.

As of version 1.1.0, Spring Data JPA ships with a custom CDI extension that allows using the repository abstraction in CDI environments. The extension is part of the JAR. To activate it, include the Spring Data JPA JAR on your classpath.

Spring is a popular Java application framework and Spring Boot is an evolution of Spring that helps create stand-alone, production-grade Spring based applications easily. @Repository A repository is a mechanism for encapsulating storage, retrieval, and search behavior which emulates a collection of objects.

Comments
  • Hello. Could you please provide the stacktrace of the exception ? Does your interface have @Repository annotation ? Did you enable JPA repositories in your configuration ?
  • Hi Mickael, the stacktrace is too long and it doesn't fit the question. I have not added the @Repository annotation and I have not enabled "JPA repositories" (I don't know what that means). Please note that everything works as expected, until the moment I try to autowire the UserRepository inside the fragment.
  • Could you please explain what "works" ? Do you mean you have no exceptions ? Or do you mean you can actually use the repositories ?
  • Hi Mikael, when I say "works", I mean that the data access works as expected. I'm currently using EntityManager and manually creating queries using the Java Persistence Query Language inside the fragments. That's the part I'd like to avoid, because now I'm implementing with EntityManager a method that I normally get for free (e.g. findByFirstNameAndLastName).
  • @NikolaosGeorgiou had you solved this?
  • @MạnhQuyếtNguyễn I had tried a similar approach which hadn't worked due to getObject() being called too early. This does work. That being said, it's not as idiomatic as @Lazy and definitely not identical, so the downvote isn't warranted.
  • getObject() being called too early. -> So you may show how do you call it early by code. If you access it like my example, it's not a problem.
  • You are right. Circular dependency problem can be solved by @Lazy but I highly doubt that @Nikolaos Georgiou has that problem. The problem statement they described does not have a circular dependency problem.
  • Hi Mickael, thank you for the help. I realise that I forgot to mention that my app is in Spring Boot 2.1.0. I'm sorry I forgot to mention it. I think what you're mentioning is already provided for me by Spring Boot.
  • This is incorrect. I'm also seeing NPEs triggered from repository fragment code when trying to access derived query methods in the base repository.