Issue
I'm upgrading spring form 4.3.3 to 5.2.7 and I'm having this exception:
Exception:
Related cause: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'MyBean' defined in com.test: Unsatisfied dependency expressed through method 'MyBean' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
code :
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@SuppressWarnings({ "unchecked" })
public MyBean MyBean(String url,
String user, String password, String id) {
return MyBean(url, user, password, id,
new HashMap<String, String>(),false);
}
PS 1: I'm using context.getBean with args to init my bean
PS 2: I'm facing this problem at the startup of the application even though im not using the bean at the startup ( I'm using @Scope("prototype") to init the bean whenever it's called)
PS 3: I didn't have the problem with spring 4.3.3
Solution
This could be due to an open issue with Spring 5.x.x version -
https://github.com/spring-projects/spring-framework/issues/21498
It talks about the issue which is specific to 5.x.x versions.
Since Spring 5.0 a @Bean can return null and the effect is to leave the bean definition in the registry, but make the value not autowirable. However, if there is another bean of the same type that is not null, it does not become autowirable. Probably it should? The exception from Spring doesn't mention the existence of either bean (the null or the not null one)
Try marking the fields as Optional so it should not fail at startup.
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@SuppressWarnings({ "unchecked" })
public Optional<MyBean> MyBean(Optional<String> url,
Optional<String> user, Optional<String> password, Optional<String> id) {
if(url.isEmpty() && user.isEmpty() && password.isEmpty() && id.isEmpty()) {
return Optional.empty();
}
return Optional.of(new MyBean(url, user, password, id,
new HashMap<String, String>(),false));
}
Update 1
I think this is more easier solution. Spring 5.0 added Nullable annotation and probably they added this annotation for this kind of scenario only.
API Documentation Link - https://docs.spring.io/spring/docs/5.0.0.RC1_to_5.0.0.RC2/Spring%20Framework%205.0.0.RC2/org/springframework/lang/Nullable.html
A common Spring annotation to declare that the annotated parameter or return value could be null under some circumstances.
So all needed would be to mark the parameters and return type as Nullable.
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@SuppressWarnings({ "unchecked" })
public @Nullable MyBean myBean(@Nullable String url,
@Nullable String user, @Nullable String password, @Nullable String id) {
if(url == null && user == null && password == null && id == null) {
return null;
}
return new MyBean(url, user, password, id,
new HashMap<String, String>(),false);
}
Answered By - SKumar
Answer Checked By - Mary Flores (JavaFixing Volunteer)