My controller contains the following annotation :
#Resource(name="userService")
private UserDetailsServiceImpl userService;
and the service itself has the following :
#Service("userService")
#Transactional
public class UserDetailsServiceImpl implements UserDetailsService {
#Resource(name = "sessionFactory")
private SessionFactory sessionFactory;
However I receive the following error on startup :
Injection of resource dependencies
failed; nested exception is
org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'userDetailsServiceImpl'
must be of type
[myapp.service.UserDetailsServiceImpl], but was actually of
type [$Proxy19]
It should be
#Resource(name="userService")
private UserDetailsService userService;
Spring uses the interface type to make dependency injection, not the implementation type
Change to (interface instead of concrete class):
#Resource(name="userService")
private UserDetailsService userService;
And live happily ever after.
Long version: at runtime, by default, Spring replaces your class with something that implements all the interfaces of your class. If you inject interface rather than a concrete type, you don't care what is the exact type implementing this interface.
In your case adding #Transactional annotation causes your bean to be replaced by AOP proxy with transaction capabilities. If you remove this annotation, your code will run fine. However, it is a good idea to depend on interfaces, not on concrete implementations.
Related
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.
I'm trying to inject a service-annotated class into a configuration class in a Spring Boot application, but it doesn't get injected (is set to null), which I assume is due to the Spring lifeycle.
Also, this service has an overloaded constructor that uses constructor injection, and I guess this is also a problem, as autowiring acts upon a default constructor. However, the service needs to be Spring-configured, so I don't think one can create a new instance in a Bean annotated method.
How can one solve this?
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private SessionService sessionService;
#Bean
public SessionService sessionService() {
return sessionService;
}
}
public interface SessionService extends BaseCacheService<Session> {
void extendExpiration(String key);
String getSessionId(String key);
}
#Service
public class SessionServiceImpl implements SessionService {
private Environment environment;
private UserService userService;
#Autowired
public SessionServiceImpl(Environment environment, UserService userService) {
this.environment = environment;
this.userService = userService;
}
}
If I exclude the #Bean method, then I get a compilation error:
Your error is the following (you are returning a null value):
#Bean
public SessionService sessionService() {
return sessionService;
}
Solution
Since your SessionServiceImpl is annotated with #Service, you can just remove the #Bean method and let spring create it. Spring already makes it available for you.
Or, If your SessionServiceImpl wasn't annotated with #Service, you would need the following :
#Bean
public SessionService sessionService() {
return new SessionService();
}
If this doesn't work, it may just be that your SessionServiceImpl is in a package not being scanned by spring (as suggested by #Miloš Milivojević)
You may add #ComponentScan to your Configuration class
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#ComponentScan("com.package.to.sessionServiceImpl-or-higher")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
Expanding on #Alex's answer, when you annotate a method with #Bean, it tells Spring that this method will produce that type. So, you essentially told Spring to give you the null reference you already had for all Beans of type SessionService.
If you are using Annotation-based context configuration, you can Autowire any #Component Bean (not just #Service) that can be constructed without runtime parameters (e.g. has a default constructor or an Autowired Constructor). If you need to do something to create the bean (e.g. runtime configuration required), you would either create a method as #Alex suggested, or you can use getBean and pass in the Type and Constructor arguments. The former is generally preferred.
I was facing similar issue while writing an integration test class for a spring boot application. RestTemplate class and CounterService of metrics API are autowired in my service class. I could use #ContextConfiguration(Classes={RestTemplate.class}) for injecting RestTemplate to my service, but adding CounterService.class to above annotation does not help, maybe because CounterService is an interface not a concrete class, Hence I was getting "No bean of type CounterService found" issue.
Thanks to answer by Milos, I included #EnableAutoConfiguration to my integration test class, issue was resolved!
If Alex's answer does not work (removing the #Bean method), you're probably not using #EnableAutoConfiguration or your Application is not in the root-hierarchy package so it's not scanning the whole classpath. Try adding #ComponentScan("service.class.package") to your configuration (in addition to removing the sessionService method) and see if it helps.
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.
I need to inject by #Autowired concrete implementation of a service class.
Service interface:
public interface PostService {
...
}
Implementation:
#Service("postServiceImpl")
public class PostServiceImpl implements PostService {
...
}
Methods in the service are with # Transactional annotation
And now I want to inject postServiceImpl to my controller - because I need to use one method from the implementation, that is not in the interface:
#Autowired
#Qualifier("postServiceImpl")
private PostServiceImpl postService;
I get NoSuchBeanDefinitionException with the following message:
No qualifying bean of type [ (...) .PostServiceImpl] found for
dependency: expected at least 1 bean which qualifies as autowire
candidate for this dependency.
when I change the field in my controller to:
private PostService postService
it works, but I can't use a specific method from PostServiceImpl.
Since your methods are annotated #Transactional, spring will create proxy at runtime, to inject transaction management code. By default Spring uses JDK Dynamic Proxy for proxying mechanism, which proxies based on interfaces.
So, in this case, spring creates another class which implements PostService interface, and creates bean of that class. Definitely that cannot be autowired to PostServiceImpl, as those are siblings. However, if you really want to autowire on class, you can force spring to use CGLib proxy instead, which proxies using subclassing. That you can do by setting proxyTargetClass=true in your #EnableTransactionManagement annotation, if you're using Java based config.
Say I need to rely on several implementations of a Spring bean. I have one AccountService interface and two implementations: DefaultAccountServiceImpl and SpecializedAccountServiceImpl.
How is this possible (injecting one or the other implementation) in Spring?
Which implementation will the following injection use?
#Autowired
private AccountService accountService;
Ad. 1: you can use #Qualifier annotation or autowire using #Resource as opposed to #Autowired which defaults to field name rather than type.
Ad. 2: It will fail at runtime saying that two beans are implementing this interface. If one of your beans is additionally annotated with #Primary, it will be preferred when autowiring by type.
#Autowired
#Qualifier("impl1")
BaseInterface impl1;
#Autowired
#Qualifier("impl2")
BaseInterface impl2;
#Component(value="impl1")
public class Implementation1 implements BaseInterface {
}
#Component(value = "impl2")
public class Implementation2 implements BaseInterface {
}
For full code: https://github.com/rsingla/springautowire/