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);
}
}
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;
}
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() {
// …
}
}
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'sDataAccessException
hierarchy.
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.
Do not include circular dependencies as it is not a good practise.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.