Spring Autowire primitive boolean - java

My XML configuration includes these bean definitions:
<bean id="abstractFormAction" class="staffing.server.action.form.AbstractFormAction" abstract="true" parent="baseAction">
<property name="volunteerSaver" ref="volunteerSaver"/>
<property name="emailSender" ref="emailSender"/>
<property name="closed" value="${form.closed}"/>
</bean>
<bean id="volunteerFormAction" class="staffing.server.action.form.VolunteerFormAction" parent="abstractFormAction">
<property name="captchaGenerator" ref="captcha"/>
</bean>
Indicating that VolunteerFormAction is a concrete implementation of AbstactFormAction, and will inherit the properties of AbstactFormAction.
In AbstractFormAction, I declare the properties like this:
#Autowired protected VolunteerSaver volunteerSaver;
#Autowired protected EmailSender emailSender;
#Autowired protected boolean closed;
I get the following exception when I try to deploy:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'volunteerFormAction': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: protected boolean
staffing.server.action.form.AbstractFormAction.closed; nested
exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
matching bean of type [boolean] 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)}
It seems to be complaining that it cannot find a bean of byte boolean. But why would it want a bean when have defined property 'closed' by value, not by reference?

You need to use #Value annotation for passing values using property place holders. #Autowire expects a bean of the specified type to be present in the applicationContext.
If you are autowiring the values why are you passing the values int he bean definition? I think what you need is
<bean id="abstractFormAction" class="staffing.server.action.form.AbstractFormAction" abstract="true" parent="baseAction"><bean>
<bean id="volunteerFormAction" class="staffing.server.action.form.VolunteerFormAction" parent="abstractFormAction">
<property name="captchaGenerator" ref="captcha"/>
</bean>
and
#Autowired protected VolunteerSaver volunteerSaver;
#Autowired protected EmailSender emailSender;
#Value("#{form.closed}") protected boolean closed;
If you can use component-scan you need not even specify create the beans
You can add <context:component-scan base-package="<your base package>"/> to your context.xml file and add the annotation #Controller to your controller file

You shouldn't annotate closed with #Autowired.
#Autowired instructs Spring to look up a bean of the type of the autowired field (boolean) in your context, that's why it's complaining about "No matching bean of type [boolean]"
If you inject the value from xml config, there is no need for any annotation on that field.

Based on the code you've shown, it's likely that you have a problem in the way you're loading your Spring contexts. My guess is that you're incorrectly component-scanning your controllers in both the root web application context and in the child context where the controllers are supposed to live. That means there are two instances of this class being created, and only one of them is being configured via the XML. Spring is attempting to autowire the other instance and failing with the given error. You'll find descriptions of the problem and solution in several other SO answers, like these:
Declaring Spring Bean in Parent Context vs Child Context
Spring XML file configuration hierarchy help/explanation
Spring-MVC: What are a "context" and "namespace"?
If you give more detail about your config files and context configuration, someone might be able to point out exactly where you're going wrong.

Related

Spring boot: #Value having issues with bean defined in dependency

I have a spring boot application, say A, which has a bean defined in xml:
<bean class="com.learning.MyBean" name="myBean">
<property name="maxAngle" value="360" ></property>
</bean>
Bean is:
public class MyBean {
#Value("${maxAngle}")
public void setMaxAngle(double maxAngle) {
....
}
}
When I run A independently, all is fine. But when I include it as dependency in another spring boot application, then I get error related to injection of maxAngle:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myBean': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'maxAngle' in value "${maxAngle}"
What can be the issue here?
#Value annotation is used to bind properties defined in application.properties or application.yaml.
Try adding maxAngle=360 to application.properties or application.yaml and remove it from bean XML defination

Autowired class from the jar file outside the classes

How can the Class in a jar file get scanned by the <context:component-scan base-package="" />. I am getting the below error for my autowired class.
SEVERE [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log StandardWrapper.Throwable
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.quartz.Scheduler com.path.controller.MyController.scheduler; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.quartz.Scheduler] 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)}
code:
package com.path.controller;
import org.quartz.Scheduler;
#Controller
public class MyController{
#Autowired
Scheduler scheduler;
}
This scheduler is inside the jar file quartz-oracle-2.1.6.jar and is under WEB-INF\lib. This lib is outside the classes folder of the deployment package. In the applicationcontext.xml i have the below entry,
<context:component-scan base-package="com.path" />
When you export the jar file using the export utility in eclipse there is a option called Add directory entries. Check this option and export the jar file, this will solve the problem
I'm guessing you haven't defined your scheduler bean. You need to first define the bean in order to inject into your controller.
In your applicationcontext.xml first define a bean with type Scheduler.
You might need something like below. Be sure to check out the quartz documentation to check which scheduler you need and how to instantiate it.
<bean id="schedulerFactory"
class="org.quartz.StdSchedulerFactory" />
<bean id="scheduler" class="org.quartz.Scheduler" factory-bean="schedulerFactory" factory-method="getDefaultScheduler" />
As the exception complains "No qualifying bean of type [org.quartz.Scheduler]" , we will have to define the bean of type org.quartz.Scheduler, But that is not possible without any concrete implementation of the same, So , we will have to get a concrete implementation from the Factory class org.quartz.impl.StdSchedulerFactory and it's non static method getScheduler().
Hence, you will have to add following two lines in you context xml file and it will work , I have verified the same with the same version of spring which you are using :
<bean id="schedulerFactory" class="org.quartz.impl.StdSchedulerFactory" />
<bean id="scheduler" class="org.quartz.Scheduler" factory-bean="schedulerFactory" factory-method="getScheduler" />
A console output after printing the initialized bean gives this :
scheduler=org.quartz.impl.StdScheduler#536aaa8d

Ambiguous autowiring but none with qualifier

I have a service, which injects a Bean with #Autowired as follows.
#Service
public class AdminServiceImpl implements AdminService {
#Autowired
private WebServiceTemplate adminServiceTemplate;
}
And an xml that holds two beans, causing ambiguous autowiring
<bean id="serviceWebClient" class="org.springframework.ws.client.core.WebServiceTemplate" scope="prototype">
<constructor-arg ref="messageFactory" />
<property name="marshaller" ref="marshaller" />
<!-- More properties -->
</bean>
<bean id="adminServiceWebClient" class="org.springframework.ws.client.core.WebServiceTemplate" scope="prototype">
<constructor-arg ref="messageFactory" />
<property name="marshaller" ref="marshaller" />
<!-- More properties -->
</bean>
This obviously causes the following exception (at startup):
No qualifying bean of type [org.springframework.ws.client.core.WebServiceTemplate] is defined: expected single matching bean but found 2: serviceWebClient,adminServiceWebClient
The weird part:
When I add the #Qualifier in my service to specify which Bean to select, it suddenly can't find any anymore. E.g. I edit my service to the following:
#Service
public class AdminServiceImpl implements AdminService {
#Autowired
#Qualifier("adminServiceWebClient")
private WebServiceTemplate adminServiceTemplate;
}
And instead of getting my specified Bean, I get the following exception message (at a later time when I retrieve the ApplicationContext with context = new ClassPathXmlApplicationContext(CONFIG_FILE);):
No qualifying bean of type [org.springframework.ws.client.core.WebServiceTemplate] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Is there any logical explanation of something this odd happening? I'm not even sure where to start debugging. It seems to find both, but still refuses to autowire one.
Edit
When removing the additional Bean from my XML and the #Qualifier annotation, I still get:
No qualifying bean of type [org.springframework.ws.client.core.WebServiceTemplate] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
But it works fine at startup. It just fails after calling:
context = new ClassPathXmlApplicationContext(CONFIG_FILE);
So at startup it seems to find it (it's required and doesn't fail), but it fails when requesting the context.
Perhaps you are actually starting two application contexts? One would have those beans present while the other wouldn't.
If this is the case, your first context would start okay when the qualifier is present but second one would fail due to the beans missing (exception #2). With no qualifier present, first context would fail to start due to two alternates.
To solve this (when starting second context) give it a parent context:
new ClassPathXmlApplicationContext(new String[]{CONFIG_LOCATION}, parentContext);
I have found out why this problem occurred. And it was a (rather stupid) mistake. In case someone else also runs into this, check out the following:
Overview
I run my application with various Spring Bean files. When my application starts, I use a "main context" file which does a component-scan of my entire base-package. Inside this "main" file I have the WebServiceTemplate Beans.
Startup
My component-scan finds my service and autowires its respectful WebServiceTemplate Bean into it. So it works fine at startup, as expected.
Runtime
When I call
context = new ClassPathXmlApplicationContext(CONFIG_FILE);
I actually call a different file. This file does not contain the WebServiceTemplate Beans but it did also contain a component-scan of the entire base-package. Causing it to find my Service, but not the beans it should autowire.
Solution
When loading the other file, I changed the component-scan to be more narrowed down to just what I need. So it doesn't scan for the service, but it gets loaded at startup.

How to autowire spring.xml defined beans into #Component Beans

I have a large Spring Project, whose beans are mostly created via the #Component annotation on classes. I'm slowly tring to move the bean definition to the spring.xml config file.
I however, get a the following error whenever I try to autowire a bean created in the xml config file into a bean created via the #Component annotation.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ComponentBean' defined in class path resource [spring.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'xmlBean' of bean class [myproject.XmlBean]: Bean property 'xmlBean' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
In my spring.xml:
<bean id="xmlBean" class="myproject.XmlBean" />
Trying to autowire beans into #Component beans as follows does not work:
#Component
class ComponentBean {
#Autowired
private XmlBean xmlBean;
// Bean setters and getters
}
Is there a way by which I could marsh up the two, as I slowly port my bean definitions to the spring.xml config file.

Can't get#Autowired to work with beans

I'm currently just starting out with Spring and trying to get the hang of it. But I've run into a problem: My #Autowired keeps failing.
In my spring.xml I've got this:
<!--Handle #Autowired-->
<context:annotation-config />
<context:component-scan base-package="org.MYPROJECT">
<context:include-filter type="regex" expression=".*"/>
</context:component-scan>
When running some tests it fails with this (I'm only showing the last exception as its the most important)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.quackbot.dao.AdminDAO] 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)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:920)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:789)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:474)
... 50 more
So I try to fix it by adding the bean manually to the config
<bean id="AdminDAO" class="org.quackbot.dao.hibernate.AdminDAOHibernate">
</bean>
Run it again, now I get this
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.quackbot.dao.AdminDAO] is defined: expected single matching bean but found 2: [adminDAOHibernate, AdminDAO]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:796)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:474)
... 50 more
Seems I just can't win when using Spring... First it complains that the beans don't exist, when specifying them it complains that there's too many. What's going on? Why can't it load the correct beans?
Do you have an annotation in your dao?
Something like #Repository or #Component right above the class to tell Spring this needs to be picked up when scanning your base package?
This is more than enough, no other XML configuration is needed in your case:
<context:component-scan base-package="org.quackbot"/>
Secondly, make sure AdminDAOHibernate implements AdminDAO.
Last but not least, double check that the field annotated with #Autowired is of type AdminDAO (interface).
Last piece of advice: add default constructor to AdminDAOHibernate and place place some logging statement there or put breakpoint. There should be only one invocation of this constructor, although it gets tricky when class proxies are involved.
Is this a Spring MVC app? One way or another, I'm guessing you have two separate Spring contexts, whether you know it or not. In one context, you have a dependency on your AdminDAO, but it isn't available, which causes your first exception. Your other context also has a dependency on AdminDAO which is already satisfied, but when you manually add another AdminDAO bean, that fails because there are two of them.
#Autowired using annotations
#Repository("ExampleDao")
public class ExampleDaoImpl implements ExampleDao
#Service("ServiceExample")
public class ExampleServiceImpl implements ExampleService
#Controller
public class ExampleController
#Autowired
private ExmpleService ServiceExample;

Categories