0

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

aabc
  • 9
  • 5
  • Does Component instead of Bean work? Do you inject MyBean with Autowired? – Milgo Aug 04 '20 at 12:20
  • thanks for your response actually i cant use **@Component** on a method "**the annotation @Component is disallowed for this location** " and no im not using **@Autowired** anywhere I'm just calling the bean with context.getBean and passing the arguments – aabc Aug 04 '20 at 13:38

1 Answers1

0

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);
  }
SKumar
  • 1,940
  • 1
  • 7
  • 12
  • thank you for mentioning the open issue in spring 5.*. Optional will be very useful if I was able to return null if non of the parameters are present ( url , id ...) but as i know i can't return null otherwise i will get another error **Bean instance of type [class org.springframework.beans.factory.support.NullBean] is not a FactoryBean**. – aabc Aug 05 '20 at 10:00
  • do you have any suggestions to handle NullBean error ( spring 5.2.7 )? – aabc Aug 05 '20 at 10:12
  • @AzizBECHINI Can you please elaborate more on NullBean error. When are you getting this ? Is it at the Server startup ? When you refer to returning null, are you returning null from your myBean method ? – SKumar Aug 05 '20 at 10:58
  • im having the error at the Server startup because in my code I have to test if the values are present to return **MyBean(url.get(), user.get(), password.get(), id.get(), new HashMap(),false);** otherwise I have to return null – aabc Aug 05 '20 at 12:07
  • Can't you return Optional of MyBean then ? So, the return type of the method will be Optional . Also, instead of returning null, simply return Optional.empty() – SKumar Aug 05 '20 at 12:10
  • @Aziz I updated the answer with what I suggested above – SKumar Aug 05 '20 at 12:16
  • thank you for your quick response, Okay so I'm going to test the application with the new changes. I'll keep you updated. – aabc Aug 05 '20 at 12:29
  • after doing some tests, first i have no problem at startup , but I had some other problems when using the bean : the type of bean that I'm going to have is **Optional** and not **MyBean** and whenever I want to init the bean I have to pass parameters as **Optional.of(StringValue)** and not **String** and these breaking changes can cause regressions in other parts of the code – aabc Aug 05 '20 at 15:04
  • @Aziz I updated the answer. Probably using Nullable should work. Let me know if this works for you. – SKumar Aug 05 '20 at 16:07
  • Unfortunately no it's not working I'm having the same kind of exception **Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'MyBean' defined in com.beanpackage: Unsatisfied dependency expressed through method 'MyBean' parameter 0** at the Server Startup – aabc Aug 05 '20 at 17:08
  • Hmmm, then I think, Optional is the only option. You could try mixing both Optional and Nullable. I mean marking return type as Nullable and String parameters as Optional. Also, If I am correct you are initializing MyBean with new operator. Why do you need to mark it as a Prototype bean ? Why can't you simply create MyBean object wherever it's needed ? – SKumar Aug 05 '20 at 17:54
  • Actually, I can't return null even with mixing @Nullable annotation with optional ( as you suggested ) **the same NullBean error** (at the startup), I can't initialize MyBean directly as an object otherwise it will be a breaking change ( I'm working on a project and my task is to upgrade spring from 4.3.3 to 5.2.7 and try to handle the problems **without** causing regression in the existing code). – aabc Aug 05 '20 at 21:05