CrudRepository inside my custom repository impleme

2019-02-03 04:13发布

I am attempting to get a reference to my repository interface (UserRepository) that extends CrudRepository within my custom implementation (UserRepositoryExtensionImpl) in order to gain access to all the methods provided by Spring JPA.

Crud Extension:

@Repository
public interface UserRepository extends CrudRepository<User, String>, UserRepositoryExtension<RosterUser> {
    ...any custom spring JPA methods...
}

Extension Interface:

@Repository
public interface UserRepositoryExtension <T> {
   public T put(T entity);
}

Custom Implementation:

public class UserRepositoryExtensionImpl implements UserRepositoryExtension<User> {

    UserRepository userRepository;

    @Autowired
    public UserRepositoryExtensionImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public User put(User user) {
        System.out.println(user + "was put");
        // ...put logic here
        return null;
    }...
}

However, I am unable to inject UserRepository since a circular dependency exists (given that UserRepository extends the interface implemented by my UserRepositoryImpl). I am getting the following error:

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name '    userRepositoryImpl': Requested bean is currently in creation: Is there an unresolvable circular     reference?

A possible, but less than ideal solution would be to inject and EntityManager into UserRepositoryImp, but in that case, I do not have access to any of the Spring JPA methods provided by CrudRepository, or any additional methods that I might have created in UserRepository.

Any suggestions on how to get around this?

Any help would be greatly appreciated.

EDIT: As mentioned in @shelley's answer, I was able to solve this by making 3 changes:

  • Removing the @Repository from UserRepositoryExtensionImpl
  • Renaming UserRepositoryExtensionImpl to UserRepositoryImpl. Apparently this makes Spring aware of the implementation's existence. See Spring Doc
  • Removing my constructor and moving the @Autowired to the userRepository field

SUCCESS!

6条回答
我命由我不由天
2楼-- · 2019-02-03 04:35

A couple small things need to be changed in order for this to work:

  • Remove the @Repository annotation from the custom repository interface (UserRepositoryExtension).

  • The custom repository implementation should actually be named "<StandardRepository>Impl" rather than "<CustomRepository>Impl". In your code example, this should be UserRepositoryImpl instead of UserRepositoryExtensionImpl.

查看更多
贼婆χ
3楼-- · 2019-02-03 04:35

As shelley pointed out, the naming is really important to make the autowire work. In the example below, I follow the right naming standard for my custom interface and its implementation. But my interface that extended the JpaRepository was named “ItemDao” instead of “ItemRepository”, this resulted in that spring ignored my custom implementation altogether...

OBS!!! Should be "ItemRepository"

@Repository
public interface ItemDao extends JpaRepository<Item, Long>, ItemRepositoryCustom {}

my interface

interface ItemRepositoryCustom {...}

my implementation class

class ItemRepositoryImpl implements ItemRepositoryCustom {...}

If anyone have similar problems, start by following the naming standard that is used in the spring documentation at the link below.

http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations

查看更多
The star\"
4楼-- · 2019-02-03 04:36

I have solved problem by injecting ApplicationContext and getting bean in lazy way using applicationContext.getBean(UserRepository.class). It works this way.

查看更多
女痞
5楼-- · 2019-02-03 04:42

I found I way of how to do it without the need for @Autowire:

public interface UserRepository extends 
    UserRepositoryBasic,
    UserRepositoryExtension 
{ 
}

public interface UserRepositoryBasic extends
    JpaRepository<User, String>
{
    // standard Spring Data methods, like findByLogin
}

public interface UserRepositoryExtension 
{
    public void customMethod();
}

public class UserRepositoryExtensionImpl implements
    UserRepositoryExtension 
{
    private final UserRepositoryBasic userRepositoryBasic;

    // constructor-based injection
    public UserRepositoryExtensionImpl(
        UserRepositoryBasic userRepositoryBasic)
    {
        this.userRepositoryBasic = userRepositoryBasic;
    }

    public void customMethod() 
    {
        // we can call all basic Spring Data methods using
        // userRepositoryBasic
    }
}
查看更多
forever°为你锁心
6楼-- · 2019-02-03 04:49

Well in this case I suggest to use the @Lazy annotation.

public class MyCustomRepositoryImpl implements MyCustomRepository {

    @Lazy
    @Autowired
    private MyRepository myRepository;

    @Override
    public boolean customMethod() {
       return myRepository.count() > 0;
    }

}

With constructor parameter Spring tries to create the "basic" repository class which require you custom repository which requires you "basic" repository - the typical case with circular dependency.

Without @Lazy but with only the @Autowired it also won't work (there will be problem with factory bean for the basic repo).

I think in this case the @Lazy is the most elegant solution.

查看更多
乱世女痞
7楼-- · 2019-02-03 04:57

There is a well defined way to create custom repository implementations in Spring Data JPA which you should follow. Basically you need to extend CrudRepository so you don't have to inject an instance of it in your custom implementation.

查看更多
登录 后发表回答