A bean defiend on the applicationContext.xml is getting instantiated using both ClassPathXmlApllicationContext and WebApplicationContext. While using the former the bean is returned as expected but while using the latter, WebApplicationContext, I'm getting a null value.
FYI: Not using the Spring to its full extent. Just used to define a bean and to intialize it. Its a web service application based on jboss.
I defined the WebApplicationContext in my web.xml as below
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<display-name>Service</display-name>
<servlet-name>MService</servlet-name>
<servlet-class>
com.xyz.atop.ws.memb.MServiceImpl
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MService</servlet-name>
<url-pattern>/Service</url-pattern>
</servlet-mapping>
</web-app>
The entry from the applicationContext.xml
<beans ...>
<context:annotation-config />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="helper" name="helper" class="com.xyz.svc.wrapper.Helper">
<constructor-arg type="java.lang.String" value="ABC"/>
</bean>
</beans>
Used the ClassPathApplicationContext (returning a bean instance as expected) in my code as below
private static Helper helper;
public MServiceImpl() {
}
static {
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
helper = (Helper) appContext.getBean("helper");
}
......
......
While using the WebApplicationContext, I tried #Autowired annotation and even tried setter injection. Both the ways I'm getting a null value returned.
The "Helper" class I'm trying to initialize is coming from a jar file which in turn makes calls to a cxf-spring application.
Please look at the above scenario and advise to get rid of the null pointer while using the WebApplicationCOntext.
Ok, spring beans are injected into other spring beans. MService needs to be a bean too. Autowire will then inject the helper into the MService bean. You can't use a static initializer to do this, because that is run at classload time, which is before the application context has loaded. Also, helper shouldn't be static -- that's bad practice -- it makes testing very difficult.
Scenario: Used WebApplicationContext to intialize the beans defined in the applicationCOntext.xml file and received a null while trying to use the instantaited bean object in the code after autowiring.
Issue in this scenario: I'm trying to autowire a spring bean in a class on which Spring has control over.
Solution:
Extending the Servlet class (Class which is not in Spring control) which is the endpoint of my JBOSS WS with Spring's SpringBeanAutowiringSupport class helped me resolve the issue.
Below is the code snippet
public class MServiceImpl extends SpringBeanAutowiringSupport implements MService{
#Autowired
private Helper helper;
public MServiceImpl() {
}
......
......
}
Figured out that using static block to initialize the spring bean is bad approach. Thanks to #Engineer Dollery
Related
I have a spring controller with an autowired object that Spring says it can't find, despite my seeing - in the log file - the bean/object for it being created in the root application context. It occurs during the deployment of the application (in Tomcat).
I tried adding #Qualifier to the #Autowired field but it didn't resolve the problem.
Controller:
package com.maha.testspring.endpoints.webrest.controllers;
import com.maha.testspring.services.TestSpringService;
#Controller
#RequestMapping("/testspring")
public class TestSpringController
{
#Autowired
#Qualifier("testSpringService")
private TestSpringService testSpringService;
...
}
war's testspring-endpoints-webrest-1.0-SNAPSHOT/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
war's testspring-endpoints-webrest-1.0-SNAPSHOT/WEB-INF/spring/servlet-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
...
<mvc:annotation-driven />
<context:annotation-config />
<context:spring-configured />
<context:component-scan base-package="com.maha.testspring.endpoints.webrest.controllers" />
</beans:beans>
war's testspring-endpoints-webrest-1.0-SNAPSHOT/WEB-INF/spring/root-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...
<bean class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>/applicationContext.testspring.services.xml</value>
</list>
</constructor-arg>
</bean>
</beans>
Service implementation class: (in jar, testspring-services-impl-1.0-SNAPSHOT.jar - in the war's testspring-endpoints-webrest-1.0-SNAPSHOT\WEB-INF\lib folder)
package com.maha.testspring.services;
import org.springframework.stereotype.Service;
#Service("testSpringService")
public class TestSpringServiceImpl implements TestSpringService {
public void testIt() { System.out.println("..."); }
}
Service interface: (in jar, testspring-services-interfaces-1.0-SNAPSHOT.jar - in the war's testspring-endpoints-webrest-1.0-SNAPSHOT\WEB-INF\lib folder)
package com.maha.testspring.services;
public interface TestSpringService
{
public void testIt();
}
applicationContext.testspring.services.xml (in jar, testspring-services-impl-1.0-SNAPSHOT.jar - in the war's testspring-endpoints-webrest-1.0-SNAPSHOT\WEB-INF\lib folder)
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:spring-configured/>
<context:annotation-config />
<context:component-scan base-package="com.maha.testspring.services"/>
</beans>
Logging - shows TestSpringServiceImpl was processed for #Service (as a candidate component when injecting dependency later on)
annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: URL [jar:file:/C:/osd/Tomcat%208.0/webapps/testspringwebrest/WEB-INF/lib/testspring-services-impl-1.0-SNAPSHOT.jar!/com/maha/testspring/services/TestSpringServiceImpl.class]
support.ClassPathXmlApplicationContext - Bean factory for org.springframework.context.support.ClassPathXmlApplicationContext#41e89deb: org.springframework.beans.factory.support.DefaultListableBeanFactory#7487b2bc
Logging shows creation of bean instance for this class:
support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'testSpringService'
support.DefaultListableBeanFactory - Creating instance of bean 'testSpringService'
support.DefaultListableBeanFactory - Eagerly caching bean 'testSpringService' to allow for resolving potential circular references
support.DefaultListableBeanFactory - Finished creating instance of bean 'testSpringService'
Error when trying to create the controller - can't find the bean to inject:
support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'testSpringController'
support.DefaultListableBeanFactory - Creating instance of bean 'testSpringController'
annotation.InjectionMetadata - Registered injected element on
class [com.maha.testspring.endpoints.webrest.controllers.TestSpringController]: AutowiredFieldElement for
private com.maha.testspring.services.TestSpringService com.maha.testspring.endpoints.webrest.controllers.TestSpringController.testSpringService
annotation.InjectionMetadata - Processing injected element of bean 'testSpringController':
AutowiredFieldElement for private
com.maha.testspring.services.TestSpringService
com.maha.testspring.endpoints.webrest.controllers.TestSpringController.testSpringService
support.XmlWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testSpringController':
Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private com.maha.testspring.services.TestSpringService com.maha.testspring.endpoints.webrest.controllers.TestSpringController.testSpringService;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type
[com.maha.testspring.services.TestSpringService] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
I had a similar problem . We solved it by keeping the CASE same . In your example you used #Qualifier("testSpringService")
and your yout service public class TestSpringServiceImpl implements TestSpringService
TRY changing it to public class TestSpringServiceImpl implements testSpringService with a SMALL t in testSpringService.
If that dont solve your problem then try annotating the parent class (Remember that annotations are not inherited from parent class to the child and in your case you have annotated the child and not its parent ) like :
package com.maha.testspring.services;
#Service("testSpringService")
public interface TestSpringService
{
public void testIt();
}
Consider the below code snippet:
#Controller
public class RestController {
#Scheduled(cron = "0 0 */* * * ?") // run every hour
public void runMeHourly() {
LOGGER.debug("RestController#runMeHourly triggered to run at: " + System.currentTimeMillis());
// Do your hourly work here
}
}
When I deploy this controller in a J2EE web server I see that the method RestController#runMeHourly() in triggered twice every hour.
I found a reference to something like this here on spring docs scheduling.
It says:
Make sure that you are not initializing multiple instances of the same #Scheduled annotation class at runtime, unless you do want to schedule callbacks to each such instance. Related to this, make sure that you do not use #Configurable on bean classes which are annotated with #Scheduled and registered as regular Spring beans with the container: You would get double initialization otherwise, once through the container and once through the #Configurable aspect, with the consequence of each #Scheduled method being invoked twice.
Is this related? Does this mean I need to Schedule the method runMeHourly() from outside the RestController?
[Edit 1: Looks like the #Configurable is something else and not contributing to the problem, and I have not used it anywhere. So there must be some other reason that is causing this behaviour]
[Edit 2:
My web.xml:
<web-app>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>com.company.module.ModuleContextListener</listener-class>
</listener>
</web.xml>
mvc-dispatcher-servlet.xml
<beans>
<mvc:annotation-driven />
<task:annotation-driven />
<context:component-scan base-package="com.company" />
<import resource="module/module-servlet.xml"/>
</beans>
module/module-servlet.xml
<beans>
<context:component-scan base-package="com.company.module"/>
</beans>
]
The com.company.module.ModuleContextListener is forcing the DispatcherServlet to look for a root application context, and since the root application context is same as mvc-dispatcher-servlet.xml its being loaded twice. Once as root context and again under DispatcherServlet with the name mvc-dispatcher.
Renaming the root context xml mvc-dispatcher-servlet.xml to applicationContext.xml and adding an empty mvc-dispatcher-servlet.xml solves the problem.
Thanks to #6ton for pointing this out.
i'm learning spring now. here's my sample code. i'm using jersey, spring, hibernate, and mysql for my REST service.
CustomerServiceImpl.java which is REST endpoint (partial code)
package com.samples.service.impl;
#Path("customers")
public class CustomerServiceImpl implements CustomerService {
private static Logger logger = Logger.getLogger(CustomerServiceImpl.class);
#Autowired
CustomerBO customerBO;
here is CustomerBOImpl.java (partial code)
package com.samples.BO.impl;
#Component
public class CustomerBOImpl implements CustomerBO {
#Autowired
CustomerDAO customerDAO;
#Autowired
CustomerAdapter customerAdapter;
CustomerDAOImpl.class
package com.samples.DAO.impl;
#Repository
public class CustomerDAOImpl implements CustomerDAO {
this is 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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:property-placeholder location="classpath*:database.properties"/>
<context:component-scan base-package="com.samples"/>
<context:annotation-config />
</beans>
this is first few lines of exception i'm getting.
http-bio-8090-exec-1] [class: CustomerServiceImpl] INFO - list all customers
[http-bio-8090-exec-1] [class: CustomerServiceImpl] INFO - customerBO is null
May 08, 2014 10:55:29 AM com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException
SEVERE: The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
java.lang.NullPointerException
at com.samples.service.impl.CustomerServiceImpl.getAllCustomers(CustomerServiceImpl.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvo
this is web.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Employee Service</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:applicationContext.xml
</param-value>
</context-param>
<context-param>
<param-name>initializeContextOnStartup</param-name>
<param-value>true</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.samples.service</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
so if i'm understanding how this works correctly, i'm configuring xml to have my components autoscanned by providing the package under which i want to run autoscan. and for objects that i want to autowire. in CustomerServiceImpl class, i use #autowired for customerBO object which should have been scanned by #Component annotation on CustomerBOImpl.class definition. can you please help why my auto-scan is not picking up autowired customerBO object?
thanks.
I suspect the problem is your CustomerServiceImpl class is being instantiated outside of Spring, either by the servlet container or explicitly in your code. You need to either have Spring instantiate it (by making it a bean, etc) or use <context:spring-configured/>. I'm not sure if the latter will work if the servlet container instantiates the object as it will likely depend on the order in which things occur...
Spring only know to autowire fields that have been marked as beans. From your code CustomerDAO is not a bean. For example to define it as a bean in the xml configuration file you need to add
<bean id="customerDao" class="com.packagesNames.CustomerDaoImpl"/> in the xml file. or to have the class annotated with #Component or to have it defined with #Bean in a #Configuration class.
Jersey 2 and Spring integration is now supported.
Jersey Docs: Chapter 22. Spring DI
Blog: Implementing Jersey 2 Spring Integration
Sample App: Jersey's Hello World Spring WebApp
However, as of this writing, Spring beans can't be injected directly into JAX-RS classes by using Spring XML configuration. Annotations (#Autowired, etc.) must be used.
I had the same problem. My injected bean in the resource class was always coming as NULL.
I spent 2 days trying to figure it out why I can't inject the Spring Bean into the JAX-RS resource class. Then I found the below in the Jersey documentation:
"Limitations:
Spring beans can't be injected directly into JAX-RS classes by using
Spring XML configuration"
Note: I was using Jersey 2 and Spring 3.x in my project.
I have a question here, how beans defined in "applicationContext.xml" could be available to controllers defined in let's say "spring-servlet.xml", so i can skip this kind of errors i have.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name '/home' defined in ServletContext resource [/WEB-INF/mmapp-servlet.xml]: Cannot resolve reference to bean 'equipementService' while setting bean property 'equipementService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'equipementService' is defined
applicationContext.xml
<?xml version="1.0" ?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="equipementService"
class="mmapp.service.SimpleEquipementService" />
<bean name="equipement1"
class="mmapp.domain.Equipement" />
</beans>
mmapp-servlet.xml
<?xml version="1.0" ?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="/home" class="mmapp.web.HelloController">
<property name="equipementService" ref="equipementService" />
</bean>
</beans>
A Spring based web-application normally has multiple runtime Spring application contexts -
A root application context(which is loaded up during the start-up of the servlet container), here is where you normally put your beans for your services - the root application context is loaded up by using a ContextLoaderListener, typically using these entries in your web.xml file:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
One or more web application contexts, which is considered a child of the root application context, holding the beans related to the UI - controllers etc. This is configured by using a Dispatcher Servlet, a special servlet provided by Spring that knows to delegate the calls appropriately to the Spring Container. The beans in the root application context are visible to the beans defined here, BUT not the other way around - this way providing a level of separation between the UI layer and the services layer . This is a typical configuration entry in web.xml file:
<servlet>
<servlet-name>lovemytasks</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/mmapp-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
If you have defined the beans this way, the equipementService should be visible to your controller.
I'm not an expert and I'm not sure if this might be a problem, but I have a suggestion.
Could you post your web application descriptor (web.xml)? Does it contain the context-param?
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
I am trying to find a better way to access beanFactory in Spring3 Web App. Right now I setup a config.xml file with all my services that my system is going to use and in the controller I ad a line of code like:
private static XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("config.xml"));
in each controller.. Does anyone know of any better way to do this?
If you're using Spring MVC, presumably you've defined a servlet in web.xml to handle the requests, like:
<servlet>
<description></description>
<display-name>dispatcher</display-name>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
In which case you should have a Spring config file named something like dispatcher-servlet.xml in your web-inf directory. Put your bean definitions in there and they will get defined and be available when the servlet starts up.
EDIT:
Importing one bean configuation file into another, from section 3.2.2.1 of the Spring reference:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
Autowiring bean example in controller:
#Controller
public class MyController {
#Autowired
private MyBeanClass myBeanName;
...
}