I have a simple app which is contains xml config, 1 spring session bean, controller. Everything works fine with an annotations, but looks like spring cannot see xml config because it cannot find Person bean?!
The question is how can i autowire beans through xml only?
Exception message:
No qualifying bean of type 'com.spring_beans_scope.beans.Person' available: expected at least 1 bean which qualifies as autowire candidate
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="id1" class="com.spring_beans_scope.beans.WelcomeBean" scope="prototype">
<!--<property name="message" value="Welcome to spring" />-->
</bean>
<bean id="person" class="com.spring_beans_scope.beans.Person" scope="session">
<property name="name" value="Raj" />
<aop:scoped-proxy proxy-target-class="true" />
</bean>
<context:component-scan base-package="com.spring_beans_scope" />
<context:annotation-config />
</beans>
Bean
//#Service("person")
//#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Person {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
The head of the controller
#Controller
public class HelloController {
#Autowired
private Person person;
This answer is based on your comment that you want to know how to do it without the use of annotations.
You can do it without annotations. You need to use the autowire attribute on your bean declaration.
autowire="byName"
This may be a bit trickier as the #Controller annotation is not configured from xml but this stack overflow post helps explain how you can configure your controller to do so.
This tutorial helps explain the different ways you can autowire from the context file directly.
Related
I have the following repository, as simple as this:
package br.com.portal.repository;
public interface UserRepository extends CrudRepository<User, Long> {
#Query("SELECT u FROM User WHERE u.login = :login")
User findByLogin(#Param("login") String login);
}
Here, it's supposed to inherit all the common crud operations defined in CrudRepository and also expose the findByLogin function.
Most examples, if not all, do not annotate such repository with the #Repository annotation. Why is that? Is there a need to implement this interface or does the #Query somehow does it behind the scenes?
Here is what I currently have:
package br.com.portal.service;
public interface UserService {
User findByLogin(String login);
}
#Service
public class UserServiceImpl implements UserService {
private UserRepository repository;
#Autowired
public UserServiceImpl(UserRepository repository) {
this.repository = repository;
}
User findByLogin(String login) {
return repository.findByLogin(login);
}
}
And the spring-mvc.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- Defines the static resources location, otherwise resource requests will result in 404 errors (not found) -->
<mvc:resources mapping="/assets/**" location="/assets/" order="0" cache-period="31556926" />
<mvc:resources mapping="/favicon.ico" location="/assets/icon/favicon.ico" cache-period="31556926" />
<!-- Defines the custom Spring components packages -->
<context:component-scan base-package="br.com.portal.repository">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />
</context:component-scan>
<context:component-scan base-package="br.com.portal.service">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
<context:component-scan base-package="br.com.portal.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<!-- JPA -->
<bean class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="default" />
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
I am not using Spring Boot.
With the current above informations, we should be able to reproduce the following error:
Error creating bean with name 'userServiceImpl' defined in file xxx: Unsatisfied dependency expressed through constructor parameter 0; nested exception is NoSuchBeanDefinitionException: No qualifying bean of type 'UserRepository'
Am I missing something?
Spring is telling you there's no bean named 'userServiceImpl', which looks correct. That text (case sensitive) doesn't exist. You should look at how to name the bean. You might just need to provide a name in the #Service annotation.
You need to tell spring to scan for repository interfaces to provide implementations for. With XML you do this by adding the namespace:
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
to the beans tag and then include this line
<jpa:repositories base-package="br.com.portal.repository"/>
inside. See this answer for more context.
You DO NOT NEED a #Repository annotation on your interface. That basically comes implicitly from extending CrudRepository
Annotate the UserRepository interface with #Repository
I'm trying to inject a bean that was defined on a XML into an annotated, It is only annotated and not declared on XML, I think that is just something that I'm missing here is my *context.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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
...
<bean id="userBusiness" class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
<property name="jndiName" value="java:global/app-common/app-common-core/UserBusinessImpl" />
<property name="businessInterface" value="com.app.common.business.UserBusiness" />
</bean>
...
<context:annotation-config/>
<context:component-scan base-package="com.app.common.jsf" />
</beans>
Here's the component:
#Component
public class AppAuthorization {
#Autowired
private UserBusiness userBusiness;
#Autowired
private AppLogin sabiusLogin;
...
#Local
public interface UserBusiness {
User listUserByFilter(User user) throws UserBusinessException;
...
#Stateless
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
#Interceptors({SpringBeanAutowiringInterceptor.class})
public class UserBusinessImpl implements UserBusiness {
#Autowired
private ProgramasUsuariosDao programasUsuariosDao;
...
When I try to access the AppAuthorization Spring says that:
Could not autowire field: private com.app.common.business.UserBusiness com.app.common.jsf.AppAuthorization.userBusiness"
Seems that the annotated bean can't see the declared one, but search and seems that I only needed to add the annotation-config to the XML, is this right? Hope some can help me.
EDIT
I think that this is the most important part of the stack trace:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.app.common.business.UserBusiness] 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:997)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:867)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:779)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:503)
... 201 more
Following the steps on the context creation I see no bean registered tha can be seen by annotations just when springs creates the context based on the xml is that I can see all the beans that wre created.
EDIT 2
This is the beanRefContext.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="contexts" class="com.app.common.spring.ClassPathXmlApplicationContext" />
</beans>
This is the class that loads the XML context files:
public class ClassPathXmlApplicationContext extends org.springframework.context.support.ClassPathXmlApplicationContext {
public ClassPathXmlApplicationContext() {
super((System.getProperty("module.context.file").split(";")));
}
}
As I said, the annotated beans cannot see the XML ones so, spring cannot autowire them.
EDIT 3
I don't have a #Configuration bean (I'm not using AnnotationConfigApplicationContext), all the config is in the XML and if I try to create one the server doesn't start, it's a legacy system with spring 3.2 and EJB 3.0 and I can't change this aspect now.
Thanks in advance!
I think you missed to specify #Component annotation for the UserBusiness class
EDIT:
Can you make the component-scan config to com.app.common instead of com.app.common.jsf
What seems to work was create a #Configuration import the xml that have the bean declaration (with #ImportResource) and don't scan it's package in XML.
For some reason if I declare the file in the XML the server don't start, it's strange because I have no definition anywhere that I'm using an annotation configuration.
When I access a bean from spring bean configuration file using BeanFactory like this:
public class Person {
private String id,address;
#Autowired
private Customer customer;
//setters & getters
}
and bean configuration file
<bean name="person" class="com.ram.spring.model.Person"></bean>
<bean class="com.ram.spring.model.Customer">
<property name="email" value="ram#adp.com"></property>
<property name="name" value="Ram"></property>
</bean>
here is the executor class
public class PersonExecutor {
public static void main(String[] args) {
BeanFactory context = new XmlBeanFactory(new ClassPathResource("Spring.xml"));
Person person = (Person)context.getBean("person");
System.out.println(person.getCustomer());
}
}
when I execute this, I got null.is BeanFactory not supported for annotations?? any ideas??
Approach 1: Include below code in your xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- Remaining bean declaration -->
</beans>
Approach 2: Remove #Autowired and inject customer in your xml file only.
<bean name="person" class="com.ram.spring.model.Person">
<property name="customer" ref="customer"></property>
</bean>
<bean name="customer" class="com.ram.spring.model.Customer">
<property name="email" value="ram#adp.com"></property>
<property name="name" value="Ram"></property>
</bean>
You have to use AnnotationConfigApplicationContext or
you have to add to yor Spring.xml to activate the annotation scan.
As #jens suggested
you should active annotation scan
<context:component-scan base-package="package_path">
</context:component-scan>
<context:annotation-config />
hope that helped
Why doesn't it work?
When using Spring with an XML context, using annotations is not activated by default. This means #Autowired, #Transactional, #PostConstruct and any other annotation you will use will simply not be exploited.
How do I fix it?
To make Spring aware of annotations, you need to add the following line:
<context:annotation-config />
Thus, Spring will search for annotations in the beans it creates and process them accordingly.
This requires activating the context namespace. At the top of your context, make sure you have all context related links and arguments1:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- Your context -->
</beans>
You do not need <context:component-scan /> in your case. This would be useful if you used full-annotation context (e.g. classes annotated with #Component). See the difference between <context:annotation-config /> and <context:component-scan /> in this answer.
Alternate solution
As Naman Gala suggested, you could also drop #Autowired completely and inject all dependencies in XML. See the related answer for more details.
1 This includes the xmlns:context attribute (xmlns = XML NameSpace) and two URLs in xsi:schemaLocation.
following the answer given in this question, I have removed the spring-webmvc.jar file from my lib to avoid a repetition with the one in the core project. However, when I do this, it seems that the #Autowired for at least a bean does not work any more.
The class having the #Autowired is the following (in which none of the field is filled):
public class SecurityUserCheckBeforeControllerHandler implements BeforeControllerHandler
{
#Resource(name = "userService")
private UserService userService;
#Autowired
private CMSPageContextService cmsPageContextService;
#Override
public boolean beforeController(final HttpServletRequest request, final HttpServletResponse response,
final HandlerMethod handler) throws IOException
{
// Code where the autowired fields are used (-> produces null pointer)
}
}
The spring configuration can be summarized as follows:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:component-scan base-package="my.package" scope-resolver="de.hybris.platform.spring.IgnoreTenantScopeMetadataResolver" />
<mvc:annotation-driven ignore-default-model-on-redirect="true" validator="validator">
<mvc:message-converters>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
<alias name="defaultBeforeControllerHandlersList" alias="beforeControllerHandlersList" />
<util:list id="defaultBeforeControllerHandlersList" >
<bean class="be.sbh.site.storefront.interceptors.beforecontroller.SecurityUserCheckBeforeControllerHandler" />
<!-- other beans in the list -->
</util:list>
<alias alias="cmsPageContextService" name="defaultCMSPageContextService" />
<bean id="defaultCMSPageContextService"
class="de.hybris.platform.acceleratorcms.services.impl.DefaultCMSPageContextService">
<!-- Properties -->
</bean>
<alias alias="userService" name="defaultUserService"/>
<bean id="defaultUserService" class="de.hybris.platform.servicelayer.user.impl.DefaultUserService" parent="abstractBusinessService">
<!-- Properties -->
</bean>
</beans>
If I follow the advise given in most of the similar questions (i.e. adding an #Component above the class that would be scanned), the bean will be created twice:
with the list given in the config file:
The autowired fields will be null which will still give a NullPointerException when the bean in the list is used
by the component-scan:
The fields are correctly autowired but the bean is not used in the list.
Strangely, if I put back the spring-webmvc.jar previously removed because of this question, the #Autowired will work as expected.
Trying to compare the stacktraces between the two configurations, I saw that the beans are created at different moments in the class org.springframework.context.support.AbstractApplicationContext during the startup of the server.
Last point: there is no error during the compilation and the startup of the server.
Do you have any idea for a solution please?
Thank you for reading me,
Laurent
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