Jersey + Spring 3 + Maven 3 + Tomcat 7 @Resource in @Component Class are always null

eclipse, jersey, maven, spring, tomcat

Solution

Spring is injecting an instance of TestService with a DAO, but that instance isn't the one that requests are going to. You're using Jersey's ServletContainer to host your Jersey app, which doesn't integrate with Spring in any way. It'll be creating instances as needed all on its own, which obviously won't be injected by Spring (without doing some bytecode weaving, anyway). I'd recommend using the SpringServlet, which is a ServletContainer that knows how to get resource classes from a Spring context. That'll clear up your problem.

Problem

I have searched and tried about everything I can think of to fix this but the Dao in the TestService class is always null. I see the Spring logs showing that the Dao is injected as well as the TestService class. I have tried running under WTP for eclipse as well as straight up in Tomcat. Both result in the same error. Can anybody please help decipher where the error is that causes the Dao to be null in the TestService Class. Versions: ``` Jersey 1.8 Spring 3.0.5Release Tomcat apache-tomcat-7.0.27 Maven 3.0.3 (r1075438; 2011-02-28 12:31:09-0500) Java 1.6.0_31 Eclipse Java EE IDE for Web Developers. Version: Indigo Service Release 2 Build id: 20120216-1857 ``` Logging - Showing the injection happening (Cut off DEBUG and ClassNames for brevity) ``` Creating shared instance of singleton bean 'dataSource' Creating instance of bean 'dataSource' Eagerly caching bean 'dataSource' to allow for resolving potential circular references Finished creating instance of bean 'dataSource' Creating shared instance of singleton bean 'jdbcTemplate' Creating instance of bean 'jdbcTemplate' Eagerly caching bean 'jdbcTemplate' to allow for resolving potential circular references Returning cached instance of singleton bean 'dataSource' Invoking afterPropertiesSet() on bean with name 'jdbcTemplate' Finished creating instance of bean 'jdbcTemplate' Creating shared instance of singleton bean 'testClassDao' Creating instance of bean 'testClassDao' Found injected element on class [test.dao.TestClassDao]: AutowiredMethodElement for public void test.dao.TestClassDao.setDataSource(javax.sql.DataSource) Eagerly caching bean 'testClassDao' to allow for resolving potential circular references Processing injected method of bean 'testClassDao': AutowiredMethodElement for public void test.dao.TestClassDao.setDataSource(javax.sql.DataSource) Returning cached instance of singleton bean 'dataSource' Autowiring by type from bean name 'testClassDao' to bean named 'dataSource' Finished creating instance of bean 'testClassDao' Creating shared instance of singleton bean 'testService' Creating instance of bean 'testService' Found injected element on class [test.service.admin.TestService]: AutowiredFieldElement for test.dao.TestClassDao test.service.admin.TestService.dao Eagerly caching bean 'testService' to allow for resolving potential circular references Processing injected method of bean 'testService': AutowiredFieldElement for test.dao.TestClassDao test.service.admin.TestService.dao Returning cached instance of singleton bean 'testClassDao' Autowiring by type from bean name 'testService' to bean named 'testClassDao' Finished creating instance of bean 'testService' ``` Error - Null Pointer Exception in TestService.java because TestClassDao is null ``` Apr 25, 2012 9:07:04 PM org.apache.catalina.core.StandardWrapperValve invoke SEVERE: Servlet.service() for servlet [jersey] in context with path [/test-service] threw exception java.lang.NullPointerException at test.service.admin.TestService.createCompanyProfile(TestService.java:35) ``` TestClassDao.java ``` package test.dao; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; import test.domain.TestClass; @Repository public class TestClassDao { private NamedParameterJdbcTemplate namedParamJdbcTemplate; private DataSource dataSource; @Autowired public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; this.namedParamJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); } public void insertTestClass(TestClass testClass) { String query = "INSERT INTO TEST_CLASS_TABLE(NAME) VALUES (:NAME)"; MapSqlParameterSource namedParams = new MapSqlParameterSource(); mapParams(namedParams, testClass); namedParamJdbcTemplate.update(query, namedParams); } private void mapParams(MapSqlParameterSource namedParams, TestClass testClass) { namedParams.addValue("NAME", testClass.getName()); } } ``` TestClass.java ``` package test.domain; import java.util.Date; import java.util.HashSet; import java.util.Set; public class TestClass implements java.io.Serializable { private String name; public TestClass(String name){ this.name = name; } public String getName() { return this.name; } } ``` TestService.java ``` package test.service.admin; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.Request; import javax.ws.rs.core.UriInfo; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import test.dao.TestClassDao; import test.domain.TestClass; @Path("/resttest") @Component public class TestService { @Context UriInfo uriInfo; @Context Request request; @Autowired TestClassDao dao; static Logger log = Logger.getLogger(TestService.class); @GET @Path("/test") public String createCompanyProfile() { TestClass test = new TestClass("MyTestName"); dao.insertTestClass(test); return "test done"; } } ``` 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" 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"> <context:annotation-config /> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:1234/testClassDatabase" /> <property name="username" value="user" /> <property name="password" value="password" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource"> <ref bean="dataSource" /> </property> </bean> <context:component-scan base-package="test"/> </beans> ``` web.xml ``` <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>jersey</servlet-name> <servlet-class> com.sun.jersey.spi.container.servlet.ServletContainer </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jersey</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app> ``` UPDATE: Added this for the web-app but it didn't change anything ``` <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> ``` pom.xml - Which I think is where the issue may lie, a dependency or something ``` <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>test-service</groupId> <artifactId>test-service</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>Test Service</name> <url>http://maven.apache.org</url> <dependencies> <!-- Jersey --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.19</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>${jersey.version}</version> </dependency> <!-- Spring 3 dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Jersey + Spring --> <dependency> <groupId>com.sun.jersey.contribs</groupId> <artifactId>jersey-spring</artifactId> <version>${jersey.version}</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.2</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.16</version> </dependency> </dependencies> <build> <finalName>test-service</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> <properties> <org.springframework.version>3.0.5.RELEASE</org.springframework.version> <jersey.version>1.8</jersey.version> </properties> </project> ``` UPDATE FIXED: My friend took a look and noticed I didn't have the param set for com.sun.jersey.config.property.packages, once we added that in, everything automagically worked. ``` <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:server-context.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>jersey-serlvet</servlet-name> <servlet-class> com.sun.jersey.spi.spring.container.servlet.SpringServlet </servlet-class> <init-param> <param-name> com.sun.jersey.config.property.packages </param-name> <param-value>service</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> ```

Original source