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.
Related
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.
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>
I'm trying to make dependencies injection for DAO and services. But I get stuck with an error "cannot find bean for metier". Here is my controller code:
#Autowired
#Qualifier("metier")
private MetierInterface metierInterface;
And my applicationContext.xml
<bean id="dao" class="com.act.cours.dao.DaoImplement"></bean>
<bean id="metier" class="com.act.cours.metier.MetierImplement">
<property name="dao" ref="dao"></property>
</bean>
I have interfaces DaoInterface.java, MetierInterface.java and implementing classes DaoImplement.java, MetierImplement.java.
It is the part of servlet-context relating to internalisation.
<context:component-scan base-package="com.project.controllers" />
<interceptors>
<beans:bean
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
p:paramName="lang" />
<beans:bean
class="org.springframework.web.servlet.theme.ThemeChangeInterceptor" />
</interceptors>
<!-- i18n -->
<beans:bean
class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
id="messageSource" p:basenames="WEB-INF/i18n/messages, WEB-INF/i18n/application"
p:fallbackToSystemLocale="false" />
<beans:bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
id="localResolver" p:cookieName="locale" />
The root-context:
<context:component-scan base-package="com.project"/>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en" />
</bean>
If I try to get message within jsp page or within controllers package everything is ok:
messageSource.getMessage("message.code", new Object[] {}, locale)
But it does not work out of the package defined in servlet-context, though messageSource bean is autowired.
Does it mean that root-context has default messageSource and in servlet-context it is overriden only for particular package?
Configuration defined in ServletContext for a specific controller always overrides the configuration of the rootContext. Also it is private to the root context.
The configuration you put in the servlet context is specific to that particular servlet/controller. If you need a global functionality for internationalization you should define the messageSource bean in the root Context.
When an ApplicationContext is loaded, it automatically searches for a MessageSource bean defined in the context. The bean must have the name messageSource. If such a bean is found, all calls to the preceding methods are delegated to the message source. If no message source is found, the ApplicationContext attempts to find a parent containing a bean with the same name. If it does, it uses that bean as the MessageSource. If the ApplicationContext cannot find any source for messages, an empty DelegatingMessageSource is instantiated in order to be able to accept calls to the methods defined above.
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>