Spring MVC no default constructor found? - java

I'm having problems with my Spring controllers - I'm getting no default constructor found - but they do have a constructor which I am trying to created via the applicationContext.xml - heres the relevant bit:
<bean id="PcrfSimulator" class="com.rory.services.pcrf.simulator.PcrfSimulator" init-method="start">
</bean>
<bean id="CacheHandler" class="com.rory.services.pcrf.simulator.handlers.CacheHandler">
<constructor-arg index="0" type="com.rory.services.pcrf.simulator.CustomGxSessionIdCacheImpl">
<bean factory-bean="PcrfSimulator" factory-method="getGxSessionIdCache">
</bean>
</constructor-arg>
</bean>
Ie. I'm creating a bean first, and then trying to pass the result of a method call from that bean into the second bean's (CacheHandler) constructor.
Here'e the start of CacheHandler:
#Controller
public class CacheHandler {
private final CustomGxSessionIdCacheImpl gxSessionIdCache;
public CacheHandler(CustomGxSessionIdCacheImpl gxSessionIdCache) {
this.gxSessionIdCache = gxSessionIdCache;
}
Here's the error I'm getting:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheHandler' defined in URL [jar:file:/users/rtorney/Documents/apache-tomcat-7.0.25/webapps/PCRFSimulator-4.0/WEB-INF/lib/PCRFSimulator-4.0.jar!/com/rory/services/pcrf/simulator/handlers/CacheHandler.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.rory.services.pcrf.simulator.handlers.CacheHandler]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.rory.services.pcrf.simulator.handlers.CacheHandler.<init>()
Any help is much appreciated!

You should either define your beans in xml or annotate them, not both (if only to avoid errors like the one you're getting).
The problem here is that you're not autowiring constructor args, so spring doesn't know what to do with your controller. It knows it has to create a bean (#Controller annotation), but it doesn't know how (no default, nor autowired constructor).
You can try to do something like:
#Controller
public class CacheHandler {
private final CustomGxSessionIdCacheImpl gxSessionIdCache;
#Autowired
public CacheHandler(CustomGxSessionIdCacheImpl gxSessionIdCache) {
this.gxSessionIdCache = gxSessionIdCache;
}
and then in xml:
<bean id="gxSessionIdCache"
factory-bean="PcrfSimulator"
factory-method="getGxSessionIdCache"/>
So it will autowire constructor parameters.
Another option is to simply create default constructor and autowire gxSessionIdCache property.

You have to add an empty default constructor :
#Controller
public class CacheHandler {
private final CustomGxSessionIdCacheImpl gxSessionIdCache;
#Autowired
public CacheHandler(CustomGxSessionIdCacheImpl gxSessionIdCache) {
this.gxSessionIdCache = gxSessionIdCache;
}
But be carefull, because it seems that you are mixing annotation based configuration (#Controller) and XML configuration. In the example above, it uses the annotation based config (so please remove the bean declaration from your XML file).

You can also get this error if you haven't activated Spring's annotation-based config. Include this in your Spring Xml:
<context:annotation-config/>

Other posters have pointed out that you can get problems if you mix autowiring/component-scanning with explicit instantiation of beans. I had a similar problem with a web application that did that. I was able to fix the problem by telling the component-scanner not to automatically instantiate a bean of the crucial class. Like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=...>
<aop:aspectj-autoproxy />
<import resource="repository.xml" />
...
<context:component-scan base-package="com.example.webserver">
<context:exclude-filter type="regex" expression="MyRepositoryImpl" />
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository" />
</context:component-scan>
</beans>
where repository.xml included the explicit bean instantiation:
<beans xmlns=...>
<bean id="password" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/comp/env/store/clientPassword" />
</bean>
<bean id="repository" class="com.example.webserver.datalayer.MyRepositoryImpl">
<constructor-arg ref="password" />
</bean>
...
</beans>

Related

Autowiring a bean defined in XML - Spring Boot

I'm new to Spring (& boot) and I'm facing the following problem. I have some Beans defined in an XML file. I can retrieve these beans using ApplicationContext.getBean(), instead I would like to Autowire them, or use them in classes which do not have access to 'ApplicationContext'
A simplified version of my project:
beans.xml:
<bean id="PartnerDao" name="PartnerDao" class="partner.dao.PartnerDAOImpl">
<constructor-arg index="0" value="${integration.username}"/>
<constructor-arg index="1" value="${integration.password}"/>
</bean>
applicationContext.xml:
<beans>
<import resource="classpath:beans.xml" />
<context:annotation-config/>
<cache:annotation-driven/>
<task:annotation-driven/>
</beans>
Application.java:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
}
PartnerService.java:
#Service
public class PartnerService {
#Autowired
#Qualifier("PartnerDao")
PartnerDAO partnerDao;
}
When I build I hit the following exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'partner.dao.PartnerDAO' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=PartnerDao)}
As I mentioned, I'm new to Spring, and have been using Spring Boot's annotations to maneuver, but my supervisor constructed this beans.xml in order to integrate with other services and I'm not sure how to autowire it.
I can always do:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
PartnerDAO partnerDao = context.getBean(partner.dao.PartnerDAOImpl.class);
But I'd rather just autowire it.
Is there any other viable solution?
Thank you.
Bean wiring corresponds to providing the dependencies a bean might need to complete it’s job. In Spring, beans can be wired together in two ways : Manually and Autowiring.
Manual wiring : using ref attribute in property or constructor tag
<bean id="PartnerDao" name="PartnerDao" class="partner.dao.PartnerDAOImpl">
<constructor-arg index="0" value="${integration.username}">
<ref bean="PartnerDao" />
<constructor-arg/>
<constructor-arg index="1" value="${integration.password}"/>
</bean>
I am not sure whether this will work or not but atleast you can try.

Redefine methods in repository with spring-data

I'm using spring-data-couchbase 2.1.2, I want add methods to a single repository.
In implementation class:
public class MyRepositoryImpl implements MyRepositoryCustom {
#Autowired
RepositoryOperationsMapping templateProvider;
....
}
I added the RepositoryOperationsMapping but the object is not injected, I have the error below:
[org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException
For spring configuration I used the spring.xml file, how add in xml file the RepositoryOperationsMapping reference?
Thanks. Bye.
I solved the issue, below a snippet my spring.xml file
<couchbase:clusterInfo login="${cluster.username}" password="${cluster.password}" id="clusterInfo" />
<couchbase:bucket bucketName="${bucket.name}" bucketPassword="${bucket.password}" id="bucket"/>
<!-- template is just using default parameters and references as well -->
<couchbase:template translation-service-ref="myCustomTranslationService" />
<bean id="myCustomTranslationService"
class="org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService"/>
<bean id="couchbaseTemplate" class="org.springframework.data.couchbase.core.CouchbaseTemplate">
<constructor-arg ref="clusterInfo"/>
<constructor-arg ref="bucket" />
<constructor-arg ref="myCustomTranslationService" />
</bean>
<bean id="repositoryOperationsMapping" class="org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping">
<constructor-arg ref="couchbaseTemplate"/>
</bean>

Inject spring bean into #Controller via applicationContext.xml

In my dispatcher-servlet.xml I defined a bean as follows:
<bean id="worplacementDAO" class="com.mycompany.maventestwebapp.db.dao">
<property name="dataSource" value="dataSource" />
</bean>
Is it possible to inject the bean into a controller via applicationContext configuration file, without using #Autowired?
Simple answer - No.
You can implement BeanPostProcessor to do something with your beans (e.g. inject dependency). Or you can manually register the bean as <bean> instead of letting component-scan do that for you. But that is all you can do.

Inconsistent NoSuchBeanDefinitionException since upgrading from Spring 3.0 to Spring 3.1

We've been seeing inconsistent NoSuchBeanDefinitionException since upgrading from Spring 3.0 to Spring 3.1. It happens to only about 2% of our hosts and even then the problem is not consistent in a single host since it might not happen after restarting the same server.
Here's the error :
nested exception is org.springframework.beans.factory.BeanCreationException: Could
not autowire field: private com.google.common.util.concurrent.ListeningExecutorService
com.amazon.ms3.container.impl.ExecutionEnvironmentImpl.functionThreadPool;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [com.google.common.util.concurrent.ListeningExecutorService]
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),
#org.springframework.beans.factory.annotation.Qualifier(value=functionThreadPool)}
| at org.springframework.beans.factory.annotation
.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues...
Here's the bean code (irrelevant code removed):
public class ExecutionEnvironmentImpl extends ExecutionEnvironment {
#Autowired
#Qualifier("functionThreadPool")
private ListeningExecutorService functionThreadPool;
public ExecutionEnvironmentImpl() {
}
public void setFunctionThreadPool(ListeningExecutorService functionThreadPool) {
this.functionThreadPool = functionThreadPool;
}
}
And here's the configuration file (irrelevant configuration removed):
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
">
<bean id="executionEnvironment" class="com.amazon.ms3.container.impl.ExecutionEnvironmentImpl" scope="prototype"/>
<!-- ThreadPool for executing tenant functions asynchronously -->
<bean id="functionThreadPool" class="com.google.common.util.concurrent.MoreExecutors" factory-method="listeningDecorator">
<constructor-arg>
<bean class="java.util.concurrent.Executors" factory-method="newCachedThreadPool"/>
</constructor-arg>
</bean>
</beans>
The Qualifier annotation isn't much of use anymore since we don't have other ListeningExecutorService defined but I don't believe it should be causing any problem.
Any ideas of what might be causing this? I've been thinking about removing the autowiring completely but I'd like to understand why this is happening in the first place.
Thanks!
This is possibly some timing-related issue in the order that Spring brings up beans in the application context. It may be worth explicitly telling Spring to create the functionThreadPool first to ensure that it is available for autowiring into the executionEnvironment. To do that, you can use the depends-on attribute:
<bean id="executionEnvironment"
class="com.amazon.ms3.container.impl.ExecutionEnvironmentImpl"
scope="prototype"
depends-on="functionThreadPool"/>
<!-- ThreadPool for executing tenant functions asynchronously -->
<bean id="functionThreadPool" class="com.google.common.util.concurrent.MoreExecutors" factory-method="listeningDecorator">
<constructor-arg>
<bean class="java.util.concurrent.Executors" factory-method="newCachedThreadPool"/>
</constructor-arg>
</bean>
</beans>
If you intend to use autowiring then you should have the <context:annotation-config> element in the configuration also - so that Spring knows to autowire the functionThreadPool into the executionEnvironment.
After trying depends-on and even wiring the bean directly like shown below :
<bean id="executionEnvironment" class="com.amazon.ms3.container.impl.ExecutionEnvironmentImpl" scope="prototype">
<property name="functionThreadPool" ref="functionThreadPool"/>
</bean>
<!-- ThreadPool for executing tenant functions asynchronously -->
<bean id="functionThreadPool" class="com.google.common.util.concurrent.MoreExecutors" factory-method="listeningDecorator">
<constructor-arg>
<bean class="java.util.concurrent.Executors" factory-method="newCachedThreadPool"/>
</constructor-arg>
</bean>
we were still seeing the same error on some occasions. The only thing that fixed it was to remove the #Autowired annotation in the ExecutionEnvironmentImpl class.
We didn't really fix the problem but more like avoiding it. I wish I could provide a better answer.

Native CXF integration in grails

Does somebody know how to integrate the cxf framework without using the cxf plugin? I have already published a simple service, but my problem is to inject existing grails service bean in the cxf jaxws bean.
In applicationContext.xml i'm using following definition
<jaxws:server id="jaxwsService" serviceClass="at.pdts.cxf.HelloWorld" address="/hello">
<jaxws:serviceBean>
<bean class="at.pdts.cxf.HelloWorldImpl">
<property name="halloService"><ref bean="helloWorld"></ref></property>
</bean>
</jaxws:serviceBean>
</jaxws:server>
The helloWorld bean is a normal grails serivce class. During startup i get following exception.
Cannot resolve reference to bean 'helloWorld' while setting bean
property 'halloService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'helloWorld' is defined
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<bean id="grailsApplication" class="org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean">
<description>Grails application factory bean</description>
<property name="grailsDescriptor" value="/WEB-INF/grails.xml" />
<property name="grailsResourceLoader" ref="grailsResourceLoader" />
</bean>
<bean id="pluginManager" class="org.codehaus.groovy.grails.plugins.GrailsPluginManagerFactoryBean">
<description>A bean that manages Grails plugins</description>
<property name="grailsDescriptor" value="/WEB-INF/grails.xml" />
<property name="application" ref="grailsApplication" />
</bean>
<bean id="grailsConfigurator" class="org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator">
<constructor-arg>
<ref bean="grailsApplication" />
</constructor-arg>
<property name="pluginManager" ref="pluginManager" />
</bean>
<bean id="grailsResourceLoader" class="org.codehaus.groovy.grails.commons.GrailsResourceLoaderFactoryBean">
<property name="grailsResourceHolder" ref="grailsResourceHolder" />
</bean>
<bean id="grailsResourceHolder" scope="prototype" class="org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder">
<property name="resources">
<value>classpath*:**/grails-app/**/*.groovy</value>
</property>
</bean>
<bean id="characterEncodingFilter"
class="org.springframework.web.filter.CharacterEncodingFilter">
<property name="encoding">
<value>utf-8</value>
</property>
</bean>
<jaxws:server id="jaxwsService" serviceClass="at.pdts.cxf.HelloWorld" address="/hello">
<jaxws:serviceBean>
<bean class="at.pdts.cxf.HelloWorldImpl">
<property name="halloService"><ref bean="halloService"></ref></property>
</bean>
</jaxws:serviceBean>
</jaxws:server>
</beans>
HelloWorldImpl.groovy
package at.pdts.cxf
import javax.jws.WebService
#WebService(endpointInterface = "at.pdts.cxf.HelloWorld")
public class HelloWorldImpl implements HelloWorld {
def halloService // inject HelloService. Initialize this bean via applicationContext.xml
public String sayHi(String text) {
return "hello " + halloService.scream(text)
}
}
HelloService.groovy
class HalloService implements InitializingBean{
static transactional = false
String scream(String text) {
text.toUpperCase()
}
// methods gets not called, so service bean is not initialized at the ws creation time
void afterPropertiesSet() {
println "------> initializing bean HalloSerivce <--------
}
}
It seems that at the moment of the jaxwsService initialization the helloWorld service bean is not available.
This needs to point to something:
<ref bean="helloWorld">
Do you have something like this defined:
<bean id="helloWorld" class="at.pdts.cxf.HalloServiceImpl" />
That error means that Spring could now find a spring bean with the alias "helloWorld."
Perhaps posting your entire spring.xml and the java code to HelloWorldImpl would help.
EDIT: Your config confirms my theory.
<ref bean= says "inject something else here". But you have not defined that bean, hence the exception No Such Bean Definition. Furthermore, I was able to make your code work by creating my own implementation of HalloService (HalloServiceImpl) with a custom scream method that returned a blank string. Then I added it to the spring configuration: <bean id="helloWorld" class="at.pdts.cxf.HalloServiceImpl" />
EDIT #2: Another way to make it work is by eliminating HalloService:
<jaxws:server id="jaxwsService" serviceClass="at.pdts.cxf.HelloWorld" address="/hello">
<jaxws:serviceBean>
<bean class="at.pdts.cxf.HelloWorldImpl" />
</jaxws:serviceBean>
</jaxws:server>
</beans>
HelloWorldImpl.groovy
package at.pdts.cxf
import javax.jws.WebService
#WebService(endpointInterface = "at.pdts.cxf.HelloWorld")
public class HelloWorldImpl implements HelloWorld {
public String sayHi(String text) {
return "hello scream!" + text
}
}
Basically your choices are: Provide Spring an implmentation of HalloService, or don't reference it in your Spring.xml.
EDIT #3: There is a misunderstanding around the purpose of InitializingBean:
From the javadoc:
InitializingBean Interface to be implemented by beans that need to
react once all their properties have been set by a BeanFactory: for
example, to perform custom initialization, or merely to check that all
mandatory properties have been set.
Implementing InitializingBean just means that afterPropertiesSet() will be called. It does not mean the Spring will automatically add this bean to your Spring Config. You still must declare the bean in your spring configuration with this line:
<bean id="halloService" class="at.pdts.cxf.HalloService" />
I missed this the first time I read your question but you are defining your bean in applicationContext.xml. When I was making a test case for your question, I was putting my bean definition in grails-app/conf/spring/resources.xml. Try creating that file and putting the following into it:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!--create the bean for the service, link to groovy service bean -->
<jaxws:server id="jaxwsService" serviceClass="at.pdts.cxf.HelloWorld" address="/hello">
<jaxws:serviceBean>
<bean class="at.pdts.cxf.HelloWorldImpl">
<property name="halloService" ref="halloService" />
</bean>
</jaxws:serviceBean>
</jaxws:server>
</beans>
As a side note, you can find more information about integrating Grails and CXF here.

Categories

Resources