Search code examples
conditional-statementsspring-4beancreationexception

@Conditional annotation causing BeanCreationException on nested beans


I am using Spring 4.x in which I am using @Conditional annotation to control the bean registration. I have classes defined as given below,

@Controller
class SchoolController{
   @Autowired
   @Qualifier("studentProcessor")
   private StudentProcessor studentProcessor;
   //Some code
}

@Component("studentProcessor")
class StudentProcessor{
   @Autiwired
   private SportService sportService;
   //Some code
}

@Component
@Conditional(ServiceCondition.class)
class SportService{
//Some code
}

class ServiceCondition implements Condition{
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
  //Some condition
}
}

When I start the Tomcat, I get this exception: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'studentProcessor': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.student.service.SportService com.student.processors.StudentProcessor.sportService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.student.service.SportService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

  1. Is this the expected behavior?
  2. If not then how do I get rid of this issue?

Solution

  • From your configuration, SportService bean is loaded based on the conditional implementation of ServiceCondition.

    So, if the matches method returns false for some reason based on your logic, then SportService is would not be created and will not be available for autowiring.

    That being said, StudentProcessor cannot have a concrete @Autowired for SportService.

    I am not fully aware of your requirement, but for you to proceed with this configuration, you need to mark autowiring as optional.

    @Autiwired
    private SportService sportService;
    //Some code
    

    to

    @Autiwired(required = false)
    private SportService sportService;
    //Some code
    

    Further, you need to check if the instance is injected or not and then use it.