Autowiring a bean defined in XML - Spring Boot - java

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.

Related

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>

JMock class mocks in Spring Context

I'd like to inject JMock mock beans from Spring XML Configuration.
I have the following test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "/application-context-test.xml")
public class CorporateInfoServiceImplTest
{
#Autowired
private Mockery mockery;
#Autowired
private CorporateInfoServiceImpl corporateInfoService;
#Test
public void createCorporateInfo() {...}
}
And such XML configuration:
<bean id="mockery" class="org.jmock.Mockery">
<property name="imposteriser">
<util:constant static-field="org.jmock.lib.legacy.ClassImposteriser.INSTANCE"/>
</property>
</bean>
<bean id="createCorporateInfoOperation" class="com.acme.corp.ws.operation.CreateCorporateInfoOperation" factory-bean="mockery" factory-method="mock">
<constructor-arg value="com.acme.corp.ws.operation.CreateCorporateInfoOperation" type="java.lang.Class" />
</bean>
<bean id="corporateInfoService" class="com.acme.corp.ws.CorporateInfoServiceImpl">
<property name="createCorporateInfoOperation" ref="createCorporateInfoOperation" />
</bean>
CorporateInfoServiceImpl and CreateCorporateInfoOperation are kind of:
public class CorporateInfoServiceImpl implements CorporateServiceInterface
{
#Autowired
CreateCorporateInfoOperation createCorporateInfoOperation;
...
}
#Component
public class CreateCorporateInfoOperation
{
#Autowired
CorporateInfoDao corporateInfoDao;
...
}
When trying to autowire the CorporateInfoServiceImpl I get the following exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.acme.corp.dao.CorporateInfoDao] 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)}
The problem is that CreateCorporateInfoOperation tries to autowire dao even when created form factory-method. How can I disable such autowiring?
Other variants of injecting mock beans in JMock are appreciated.
Thanks in advance

Nested autowiring in JUnit test not working

I'm developing a spring application using JavaFX (I'm NOT using Spring MVC) and I have standard separation of concerns with controllers - services - DAOs. I'm using JdbcTemplate. I'm willing to write down jUnit tests for one of my services (I have already did it for some of them). The specific thing is that the service is autowiring two DAOs(one of which uses transactions itself) and furthermore it has one method, which is #Transactional. This is how my test exactly looks:
package org.impactvolunteers.management.service.impl;
imports ...;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:testContext.xml" })
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class RegisterVolunteerServiceImplTest extends
AbstractRegisterVolunteerServiceTest {
#Autowired
private RegisterVolunteerService registerVolunteerService;
#Before
public void setUp() {
setRegisterVolunteerService(registerVolunteerService);
}
}
And my Service implementation:
package org.impactvolunteers.management.service.impl;
imports ...;
public class RegisterVolunteerServiceImpl implements RegisterVolunteerService {
#Autowired
private VolunteerDao volunteerDao;
#Autowired
private UserDao userDao;
#Transactional(rollbackFor = { ServiceException.class,
ValidationException.class })
public Volunteer registerVolunteer(User user, Volunteer volunteer)
throws ServiceException, ValidationException {
UserValidator.validateData(user);
VolunteerValidator.validateData(volunteer);
try {
User ret = userDao.create(user);
volunteer.setUser(ret);
return volunteerDao.create(volunteer);
} catch (PersistenceException e) {
throw new ServiceException(e.getMessage(), e);
}
}
}
And in application-Context:
<context:component-scan base-package="org.impactvolunteers.management"/>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
...
<bean id="registerVolunteerService" class="org.impactvolunteers.management.service.impl.RegisterVolunteerServiceImpl" >
</bean>
Here is the error message:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'org.impactvolunteers.management.service.impl.RegisterVolunteerServiceImplTest':
Injection of autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private
org.impactvolunteers.management.service.RegisterVolunteerService
org.impactvolunteers.management.service.impl.RegisterVolunteerServiceImplTest.registerVolunteerService;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
[org.impactvolunteers.management.service.RegisterVolunteerService]
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.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
............
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
[org.impactvolunteers.management.service.RegisterVolunteerService]
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:988)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:858)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:770)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
... 28 more
And my test-Context.xml:
<context:annotation-config/>
<context:component-scan base-package="org.impactvolunteers.management"/>
<bean id="jdbc" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Spring JDBC Utility for in-memory database -->
<jdbc:embedded-database id="dataSource" type="HSQL"/>
Two strange things I noticed:
I have no problem starting the application as Java application and the service works as intended. I have only problems testing the service as jUnit test.
A service with the exact same context (and the same context for the test as the test showed here) and bean definition is being successfully tested with the only difference that it does not contain #Transactional annotations, where some of the DAOs under it do (VolunteerDaoImpl which implements VolunteerDao does contain a #Transactional annotation).
The class RegisterVolunteerServiceImpl must be annotated as service.
If the class is not annotated as a service it will not befound by the component-scan. So the bean with the name is not instanciated and can not be autowired.
In your main application-context you add the bean without component-scan
<bean id="registerVolunteerService" class="org.impactvolunteers.management.service.impl.RegisterVolunteerServiceImpl" >
</bean>
That testContext.xml doesn't import your general-purpose application context, and it also doesn't define that registerVolunteerService bean.

Spring MVC no default constructor found?

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>

Spring Bean Autowiring error

I am trying to implement email functionality in my app but I keep getting
No matching bean of type [org.springframework.mail.javamail.JavaMailSenderImpl] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Can anyone point out what I am doing incorrectly?
The xml config for the bean is:
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<context:annotation-config/>
//...other stuff
<beans:bean id="mailSession" class="org.springframework.jndi.JndiObjectFactoryBean">
<beans:property name="jndiName" value="EmailServer" />
</beans:bean>
<beans:bean id="emailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<beans:property name="session" ref="mailSession"/>
</beans:bean>
EmailServiceImpl class:
#Service
public class EmailServiceImpl implements EmailService {
#Autowired
private JavaMailSenderImpl emailSender;
//more code..
}
I was struggling with this very problem for an email service class coded like:
#Service("emailService")
public class EmailService {
#Autowired private JavaMailSenderImpl mailSender;
...
public void send(...) {
// send logic
}
}
I stumbled across a solution while reading about a related topic. The key point is that JavaMailSender interface is defined in the applicationContext.xml as the Spring JavaMailSenderImpl class.
Step 1: The application context file was modified to include the following bean definition:
<bean id="mailSender"
class="org.springframework.mail.javamail.JavaMailSenderImpl"
p:host="myMailserver.mycompany.com" />
Step 2: The email service class was modified to look like:
#Service("emailService")
public class EmailService {
#Autowired private JavaMailSender mailSender; // Observe the change in the type
...
Voila! Spring is happy. I would though like to hear a proper explanation of the original error.
Thanks to everyone for their responses. I was unable to get the autowiring to work, but I got the overall email solution to work by doing the following:
setup the mailSession in weblogic, with a jndi name of "myMailSession"
add to servlet-context.xml:
<beans:bean id="mailSession" class="org.springframework.jndi.JndiObjectFactoryBean">
<beans:property name="jndiName" value="myMailSession" />
</beans:bean>
<beans:bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<beans:property name="session" ref="mailSession"/>
</beans:bean>
<beans:bean id="emailServiceImpl" class="com.name.here.business.EmailServiceImpl">
<beans:property name="mailSender" ref="mailSender"/>
</beans:bean>
add to web.xml:
<resource-ref>
<description>the email session</description>
<res-ref-name>myMailSession</res-ref-name>
<res-type>javax.mail.Session</res-type>
<res-auth>Container</res-auth>
</resource-ref>
add to weblogic.xml:
<resource-description>
<res-ref-name>myMailSession</res-ref-name>
<jndi-name>myMailSession</jndi-name>
</resource-description>
EmailServiceImpl:
#Service
public class EmailServiceImpl implements EmailService {
private JavaMailSender mailSender;
public void setMailSender(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
//..other code
}
You need to add <context:annotation-config/> to your config file in order for Spring to autowire annotated beans.
http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config
From error message, I can conclude that autowiring is working , but its not able to find the required bean.
Make sure you load all the bean definition files.
Do you have a #Service or similar annotation on your JavaMailSenderImpl class itself? This will cause Spring's component scanner to put an instance of it in the spring container, which it can then autowire onto the EmailServiceImpl.
This is how I fixed it:
I ran into this issue too, I tried to follow simple tutorials online that worked perfectly during testing by loading the app-context.xml file manually but when I tried to run my spring mvc app it kept showing this error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.springframework.mail.javamail.JavaMailSender] 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:952)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:821)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:735)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
... 42 more
After trying all kinds of things, I happened to move these two lines from my JPA/DB configuration file to the bottom of my root-config file.
<context:annotation-config/>
<context:component-scan base-package="my.app.service.layer"/>
I'm still learning Spring but I'm thinking there was an issue regarding the order in which they appear.
Edit:
This question seems to clarify the issue with the order:
Difference between applicationContext.xml and spring-servlet.xml in Spring Framework

Categories

Resources