What is the bean ID of spring bean implements an interface - java

When the bean is createt for a class as MyBean the bean id is myBean but what will be the bean ID if I create the service bean from an interface like below?
#Service
public class ProfileServiceImpl implements ProfileService
When I try to access the bean as #profileService thymeleaf gives the below error.
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'profileService' is defined
All this time I'm using this bean by autowiring to the controller. But at the moment I need to access this from the thymeleaf.
My thymeleaf code segment
<div th:unless="${#profileService.isMe(user)}">

When Spring creates a Bean Definition from a #Service or #Component annotation, it will by default create an id for the bean by lowercasing the first letter of the Class Name. If you want to override that the behavior, you can provide an alternative id in the annotation, eg. #Service("profileService").
Regarding what you are experiencing with the Repository - by default Spring looks for a custom implementation of a Repository by appending "Impl" to the Repository Interface name. If it finds it, it will not create a default implementation. So, if you had UserRepositoryImpl extends UserRepository instead of UserRepositoryImpl extends DatatablesCriteriasRepository than Spring wouldn't have created the userRepository bean. Addtionally, if you add #NoRepositoryBean annotation to the UserRepository interface, that will suppress the creation of the userRepository bean.
However, UserRepositoryImpl really should be implementing UserRepository. If it really is intended to extend DatatablesCriteriasRepository, than it should be nameed DatatablesCriteriasRepositoryImpl. Having UserRepsitoryImpl extend DatatablesCriteriasRepository is indication of a problem in the design.

for (String name : context.getBeanDefinitionNames()){
System.out.println(name);
}
This test revealed some interesting outcomes.
service beans
Service beans are named after the concrete class name regardless of the interface.
#Service
public class ProfileServiceImpl implements ProfileService
ie. profileServiceImpl in the above question.
Repository beans
Further Repository beans are something more interesting. Below is my crud repository interface without any annotations.
public interface UserRepository extends CrudRepository<User, Long>, DatatablesCriteriasRepository<User>{
And I created an implementation of the UserRepositoryImpl for the DatatablesCriteriasRepository as below without any annotations.
public class UserRepositoryImpl implements DatatablesCriteriasRepository<User>
these two included two beans with IDs userRepository userRepositoryImpl respectively.

Related

NoUniqueBeanDefinitionException thrown though there is only one implementation

I have a MyService class which has repository field supposed to be injected.
public class MyService {
#Autowired
private MyRepository repository;
// ...ommited
}
And there is MyRepository interface only implemented by MyRepositoryImpl class with #Mapper annotation of MyBatis.
public interface MyRepository {
// ...ommited
}
#Mapper
public interface MyRepositoryImpl extends MyRepository {
// ...ommited
}
When I try to start SpringBootApplication, NoUniqueBeanDefinitionException is thrown.
#SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
#MapperScan(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
(...omitted)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'com.example.MyService':
Unsatisfied dependency expressed through field 'repository';
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'com.example.MyRepository' available:
expected single matching bean but found 2: com.example.MyRepositoryImpl,com.example.MyRepository
(...omitted)
Why is MyRepository interface registered as one of bean even though it doesn't have #Component annotation nor isn't included any bean configurations?
And I found that everything work fine if I don't use FullyQualifiedAnnotationBeanNameGenerator as nameGenerator.
Any ideas?
There can be many other ways to mark an interface as a bean. Some of them are:
#RepositoryDefinition above MyRepository interface
MyRepository extends CrudRepository or JpaRepository
Check if any of these exist.
Update 1:-
The problem seems to be in #MapperScan. What it does is scans for all the interfaces in a package and register them as bean; and if I am not wrong MyRepository and MyRepositoryImpl are in the same package. That's the reason why 2 beans are being created with names com.example.MyRepositoryImpl, com.example.MyRepository and basically both are of same type as MyRepositoryImpl extends MyRepository.
Now when you are using #Autowired on repository field of MyService, it gets confused as in which one to inject. To resolve this the easiest approach is to use #Primary over MyRepositoy which will give that interface a priority while injecting. Another approach is to use #Qualifier("uniqueName") over both the interfaces and also above repository field of MyService along with #Autowired specifying which one you want to inject. You can visit official documentation from here to learn more.Hope this helps a bit .
Spring is not able to figure out the bean whose class is supposed to be implementing the Repository interface.
Put the annotation #Repository above the RepositoryImpl Class. It will find it.

Correct inheritance in spring data repositories

I have to implement custom repository class annotated with #Repository which should inherit another class which is annotated #Repository as well.
What is correct implementation of that usecase? Can directly inherit that class and add #Repository to main, or there is another best practice? Actually I have problem when I have defined
#EnableJpaRepositories(basePackages = { "com.example.foo.repositories", "com.example.bar.repositories" }
in #Configuration class in root it doesn't scan my repositories and I can't autowire it.
here is sample of my repository class:
parent repository (third party class):
#Repository
public abstract class ParentRepository {
// ...
}
interface and impl class which are in package com.example.foo.repositories:
public interface IFooRepository {
Foo getFoo();
}
#Repository
public class FooRepository extends ParentRepository implements IFooRepository {
Foo getFoo() {
// ...
}
}
Do you have idea how to fix it and make possible to autowire IFooRepository ?
Thank you in advice.
EDIT:
I find out green bean next to #EnableJpaRepositories and when I click on the bean it redirects me to bar repository, and doesn't show FooRepository Bean. I don't understand because both repositories are identical implemented.
According to the doc for jpa repositories
In the preceding example, Spring is instructed to scan com.acme.repositories and all its subpackages for interfaces extending Repository or one of its subinterfaces. For each interface found, the infrastructure registers the persistence technology-specific FactoryBean to create the appropriate proxies that handle invocations of the query methods.
see
So basicly #EnableJpaRepositories - is the same as xml configuration from the link - it instructs to find classes that extending Repository. In you example you have #Repository annotation - that instructs Spring to translate exceptions. You should includ "com.example.foo.repositories", "com.example.bar.repositories" into components scan. Try #ComponentScan annotation see
Adding the #Primary annotation to your custom repository should autowire it into another class whenever possible by default, even if there are other valid beans for the autowire.

Spring Data CrudRepository as method Bean

Is there a way to create Spring Repository as Bean in configuration class? So that I can have multiple repositories in one class instead of creating new interface file for each entity?
I tried to create a nested #Repository interface but that couldn't been autowired.
Edit:
tried (as said earlier)
#Repository
public static interface CustomerRepository extends JpaRepository<Customer, Long> {
List<Customer> findByLastNameStartsWithIgnoreCase(String lastName);
}
which is inner class in SpringBootApplication class. I cannot use #Bean annotation beacuse it gives compilation errors
Turns out there is a method considerNestedRepositories.

Spring injection by type: two #Repository with same name

I have this pair of daos:
package com.company.project.model.requests.type;
#Repository("requestTypeDao")
public class RequestTypeDaoHibernate extends AbstractReadDao implements RequestTypeDao {
}
package com.company.project.model.support.type;
#Repository("requestTypeDao")
public class RequestTypeDaoHibernate extends AbstractReadDao implements RequestTypeDao {
}
and I'm trying to inject them in some XXXServiceImpl classes (never both in the same class) like this:
#Autowired
private RequestTypeDao requestTypeDao;
Because they are not the same type, I was expecting Spring to inject based on the imported type from the corect package (there are never imported two RequestTypeDao from the same package), but it shows an error:
Annotation-specified bean name 'requestTypeDao' for bean class [com.company.project.model.support.type.RequestTypeDaoHibernate] conflicts with existing, non-compatible bean definition of same name and class [com.company.project.model.requests.type.RequestTypeDaoHibernate]
At the error you can see the class is not the same. I have read about the #Qualifier annotation but I understand it would imply changing the name in written in the #Repository annotation. I also think that #Resource or #Inject are not what I looking for.
We don't mind changing names in the end, but we want to know if real injection by type can be made through Spring. This is two repositories with same name and different class types and packages being injected in distinct and different classes (never the same one).
Actually this is impossible. There's no way to register two same named beans into the spring. You have to use #Qualifier Otherwise spring can't handle which bean you want in the runtime.
You can learn more here
#Autowired
#Qualifier("personA")
private Person person;
#Autowired
#Qualifier("personB")
private com.blabla.myOtherPackage.Person person;

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