Here is my Resource element in context.xml ::
<Resource name="jdbc/myoracle" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@localhost:1521:XE"
username="hr" password="hr" maxActive="20" maxIdle="10"
maxWait="-1"/>
Here is my Resource reference in web.xml:
<resource-ref>
<description>Oracle Datasource</description>
<res-ref-name>jdbc/myoracle</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
I then use @Resource
annotation in my code:
@Resource(mappedName = "jdbc/myoracle")
DataSource ds;
When I try to create connection object using getConnection() on ds, I get a null pointer exception during runtime:
Oct 24, 2011 12:18:21 PM org.apache.catalina.core.StandardWrapperValve invoke
INFO: java.lang.NullPointerException
at jdbc.patientDaoImpl.get_patients(patientDaoImpl.java:248)
at org.apache.jsp.index2_jsp._jspService(index2_jsp.java:92)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:419)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:333)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:223)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:563)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:399)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:317)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:204)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:311)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
But if I lookup using initialContext the app works fine.
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/myoracle");
Where am I going wrong?
Tomcat itself does not support @Resource
injection. In other words, the servlet container does not recognize that annotation and can't do anything with it. Manual lookup works, because the resource is defined properly.
You need some dependency-injection framework:
- spring
- CDI (part of the JavaEE6 web-profile)
- EJB (part of the JavaEE6 web-profile, not exactly a "DI framework")
Note Tomcat does support @Resource
injection. You were really really close.
The issue was you used:
@Resource(mappedName = "jdbc/myoracle")
This would have worked:
@Resource(name = "jdbc/myoracle")
I'll note that had you been using Apache TomEE (the JavaEE certified version of Tomcat), both would have worked with no changes to your context.xml
Plus you get CDI, EJB, JPA and other things mentioned in some of the other answers.
Small comparison here.
There are a lot of things going on here. First off, you don't need a resource-ref in your web.xml unless you're going to let the application server manage the data source. This is useful if you use something like IBM WAS, or Apache Tomcat, and specify the data source parameters in your server config. If you do this, you'll want to keep the resource ref, and add a jndi factory bean:
<bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>java:comp/env/jdbc/myOracle</value></property>
</bean>
Coincidentally, I'm pretty sure your set up will work now if you simply add this bean.
From what you have now, or if you use a jndi factory bean, all you have to do is autowire the bean from there:
@Autowired
@Qualifier("myDataSource")
DataSource dataSource;
If you would like to verify the state of your bean, you could always implement InitializingBean
which will force you to implement afterPropertiesSet
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(dataSource);
}
Although 1@Autowired` should through an exception if it can't autowire by default.
It's also worth noting that it's a better paradigm to use a constructor:
@Autowired
public MyClass(@Qualifier("myDataSource") DataSource dataSource) {
this.dataSource = dataSource;
}
来源:https://stackoverflow.com/questions/7878835/getting-null-pointer-exception-resource-annotation-in-tomcat-7