CrudRepository inside my custom repository implementation - java

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!

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.

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

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.

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

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
}
}

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.

Related

How to properly inject #Autowired between Spring Boot classes?

I have a classA which implements an interfaceA, with a methodA, then I have a classB in which I call classA with an #Autowired to be able to use methodA, but it gives me a warning that I must create a method for classA. Why is this happening? Doesn't #Autowired work like this in this case? Should I just instantiate classA? Thank you very much for your answers.
ClassA
#RequiredArgsConstructor
public class RepositoryImpl implements IRepository {
#Autowired
private final TransactionDataMapper transactionDataMapper;
#Autowired
private SpringDataColminvoice springDataColminvoice;
#Override
public <S extends TransactionDto> S save(S s) {
Colm colm = transactionDataMapper.toEntity(s);
//methodA
springDataColminvoice.save(colm);
return null;
}
}
InterfaceA
public interface IRepository extends IRepository<TransactionDto, Integer> {}
ClassB
#Service
#RequiredArgsConstructor
public class ServiceImpl implements IInvoiceService {
#Autowired
private RepositoryImpl repositoryImpl;
#Override
public void save(CMessage cMessage) throws HandlerException {
try {
TransactionDto transactionDto = cMessage.getTransaction();
// methodA
repositoryImpl.save(transactionDto);
} catch (Exception e) {
throw new HandlerException(e.getMessage());
}
}
}
Exception
Action:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field RepositoryImpl in com.st.ms.yyu.d.binvoce.infraestructure.rest.spring.services.impl.InvoiceServiceImpl required a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.ServiceImpl' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.RepositoryImpl' in your configuration.
(posting this as an answer since I do not have enough reputation to comment)
As others have pointed out already, a code sample would help tremendously.
That being said, though, it sounds like you're missing implementation for "ClassA".
If you have an interface that "ClassA" implements, you have to implement the interface's methods in "ClassA" before you can use them.
I assume your code currently looks somewhat like this?
public interface InterfaceA {
void methodA();
}
public class ClassA implements InterfaceA {
}
public class ClassB {
#Autowired
ClassA classA; // Cannot use {#link InterfaceA#methodA} because the class does not implement the function
}
If this is your code, make sure you add an implementation for your "methodA()" function in "ClassA". Somewhat like so:
public class ClassA implements InterfaceA {
#Override
public void methodA() {
}
}
Additionally, in order to autowire in Spring (Boot), you need to ensure that the class you'd like to autowire is marked as such. You can autowire beans.
To make "ClassA" in the example eligible for autowiring, make sure to instantiate it either as:
A bean (using the #Bean annotation).
A component (using the #Component annotation).
A service (using the #Service annotation).
Any of the other annotations that may match your use case the best.
In our example, this would look somewhat like this:
#Component // Or #Service / whatever you may need
public class ClassA implements InterfaceA {
#Override
public void methodA() {
}
}
Hope you've found any of this helpful. All the best!
-T
As what I have understood, #Autowire means injecting the value/instance of the specific property where you put the annotation #Autowire. In this case, #Autowire only happens when there is defined/created Bean within your basePackage of your Spring Boot project that can match it, i.e. where your #Autowire referred to (meaning there is no conflict issue like ambiguity, etc. and the DataType(Class) can be implicitly casted). In your example, first you treat the IRepository and/or RepositoryImpl as Repository without using the #Repository annotation to inform the Spring Boot default configuration that this is a Repository bean. As you didn't put the POM.xml or posted the related code, I presumed you are creating your own repository class. I think it's much better to post your dependencies here.
But as what others pointed out. You need to create a bean that can match the #Autowired you've put on TransactDataManager & SpringDataColminvoice. You need also to inform the Spring Boot or register it that your class A is a Bean by annotating
#Bean - defining a regular bean,
#Component - a Component in the Project,
#Service - a Service in the Project,
#Repository - a Repository (if you're using Spring JPA), etc.
#<Other Annotations depending of what other Spring Project/Dependencies your using>
Since newer versions of Spring is moving to annotation based from XML mapping, we need to put proper annotation for each class/object that we want to be auto injected/instantiated from #Autowired using the above sample annotations depending on the role/purpose of your class/object is.
I suggest if you're not sure. Then create a typical bean using common annotation #Bean. So your class A might be
#Component //Insert proper Annotation for your class if necessary. This is just a sample
#RequiredArgsConstructor
public class RepositoryImpl implements IRepository {
#Autowired
private final TransactionDataMapper transactionDataMapper;
#Autowired
private SpringDataColminvoice
springDataColminvoice;//segunda
#Override
public <S extends TransactionDto> S save(S s) {
//Some implementation
}
#Bean
private TransactionDataMapper getTransactionDataMapper(<Some parameters if needed>){
return <an instance for TransactionDataManager>;
}
#Bean
private SpringDataColminvoice getSpringDataColmInvoice(<Some parameters if needed>){
return <an instance for SpringDataColminvoice>;
}
}
Note that 2 beans definition are optional if there are already a Beans define on outside class or if it was marked by other annotation like #Service, #Component or other proper annotations and the other one bean is just a reference parameter for the other bean in order to properly instantiated.
In your class B is the following:
public class ClassB {
#Autowired
ClassA classA;
/*Note: ignore this Bean definition if Class A is annotated with #Component,
#Service, or other proper #Annotation for Class A.
*/
#Bean
private ClassA getClassA(<Some Parameters if Needed>){
return <Instance of Class A>
}
}
Take note that, you don't need to put a Bean definition inside the Class B if you put a proper annotation for your Class A like #Component, #Service, etc.

CustomRepositoryImpl for Spring Data JPA Showing "Never Used" in IntelliJ

I created a custom implementation of a repository using the Spring Data Annotations and autowiring. The base repository interface is below and is controlled by Spring annotations.
#Repository
#Transactional
public interface BasicRepository extends JpaRepository<BasicMaster, Long>, BasicCustomRepository {}
The custom repository interface is:
public interface BasicCustomRepository{
List<BasicResponse> getBasic(BasicRequest basicRequest);
}
and the custom repository implementation is:
public class BasicCustomRepositoryImpl implements BasicCustomRepository {
///CODE
}
This code works as expected but for some reason, IntelliJ says "Class BasicCustomRepositoryImp is never used". How do I get IntelliJ to recognize that this is an implementation of a used interface?
It turns out that the custom repository and the implementation must have a Spring type annotation. In this case, #Repository. Spring is then able to correctly identify it and use spring based bean injection. so
#Repository
public interface BasicCustomRepository{
List<BasicResponse> getBasic(BasicRequest basicRequest);
}
and
#Repository
public class BasicCustomRepositoryImpl implements BasicCustomRepository {
///CODE
}

Spring: Trouble Autowiring services implementing a base interface

I am bit puzzled by the way spring instantiates and Autowires the services.
Basically, I am looking to find a solution to the below problem which is blocking my app to start.
Field titleService1 in com.scorpio.spring.security.oauth2.controller.TitleController required a single bean, but 2 were found:
- genderServiceImpl: defined in file [\spring\authorities\target\classes\com\spring\security\service\GenderServiceImpl.class]
- titleServiceImpl: defined in file [\spring\authorities\target\classes\com\spring\security\service\TitleServiceImpl.class]
I have two Rest controllers namely TitleController and CompanyController with each controller referencing one or multiple services. The services are the implementation of BaseService<T>
TitleController.java
#RestController
#RequestMapping("/secured/title")
public class TitleController {
#Autowired
private BaseService<Title> titleService;
}
CompanyController.java
#RestController
#RequestMapping("/secured/company")
public class CompanyController {
#Autowired
private BaseService<Title> titleService;
#Autowired
private BaseService<Gender> genderService;
}
BaseService.java
public interface BaseService<T> {
T get(Integer id);
T get(String t);
List<T> getAll();
void create(T t);
T update(T t);
void delete(Integer id);
void delete(T t);
}
Looking at the error required a single bean, but 2 were found and since there are two different implementation of BaseService, I do understand that Spring is unable to decide which Bean to Autowire as none of the implementation is annotated with #Qualifer, #Primary etc.
But what is more confusing is that, when I comment out the titleService from TitleController and re run my app, it just works. My question is how spring is able to Autowire the appropriate services in CompanyController and why if I try to Autowire in TitleController, it doesn't work ?
Many thanks.
Use qualifier annotation along with autowired. Qualifier is used to specify which implementation of interface to use.
#Autowired
#Qualifier("Audi")
private Car car;

#Primary equivalent for autowired Spring JPA repositories

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.
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.
Can I somehow tell Spring (via annotation on the repository or via
configuration) which repository to use?
Yes you can. First you give each repository class a unique bean name.
#Repository("myARepository")
public ARepository extends Repository<A, Long> {
}
#Repository("myBRepository")
public interface BRepository extends ARepository {
}
Then when you autowire using ARepository as a type you should use the #Qualifier annotation to tell Spring which of the repositories you want.
#Autowire
#Qualifier("myBRepository")
private ARepository repository;
This will autowire a BRepository

Is there a reason that we give spring annotation a name?

I noticed when using annotation for spring or spring mvc, some programmers give the annotation a name along with it. For example:
#Repository("customerRepository")
public class CustomerRepositoryImpl implements CustomerRepository{
}
I believe the class functioning the same without giving the #Repository a name. Would there be a situation that name the annotation useful?
It is mainly meant for solving ambiguity when performing an auto-scan and using #Autowired. I gave a thorough answer explaining about #Autowired in this answer which also explains about the need to name the beans.
Let's assume we have 2 classes that implement CustomerRepository:
#Repository
public class MyCustomerRepositoryImpl implements CustomerRepository {
}
#Repository
public class OtherCustomerRepositoryImpl implements CustomerRepository {
}
Let's now assume we have a class that uses #Autowired to inject a CustomerRepository:
public class SomeClass {
#Autowired
private CustomerRepository customerRepository;
}
When performing an auto-scan, you need to have a way to differentiate between them. Otherwise Spring would throw an exception saying that it can't tell which of the beans should be injected.
So we can now add a logical name to each implementation:
#Repository("myRepository")
public class MyCustomerRepositoryImpl implements CustomerRepository {
}
#Repository("otherRepository")
public class OtherCustomerRepositoryImpl implements CustomerRepository {
}
And now you can help Spring solve the ambiguity as follows:
public class SomeClass {
#Autowired
#Qualifier("myRepository")
private CustomerRepository customerRepository;
}
It helps to convert the entity into a Spring bean, if autodetected.
From the official doc here:-
The value may indicate a suggestion for a logical component name,
to be turned into a Spring bean in case of an autodetected component.
The AnnotationBeanNameGenerator is responsible for picking a name for your beans. If you specify a name you can use a different convention for your bean names than what would otherwise be generated based on the class name.
Auto-generated bean names are not fool proof; two classes with the same name can cause a duplicate bean definition, as can two classes inheriting the same interface.
The use of explicit names also ensures that code refactoring does not implicitly break the bean wiring.

Categories