I'm trying to inject DataSource
from Tomcat 8.5.56 using the @Resource
annotation, but when I run the code I get NullPointerException.
Note: Getting DataSource
with InitialContext
still works fine.
Resource definition in context.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/postgres" auth="Container"
type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost:5432/contact_directory"
username="username" password="password" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/>
</Context>
The servlet for testing:
@WebServlet(name = "TestController", urlPatterns = "/test")
public class TestController extends HttpServlet {
//this also doesn't work
//@Resource(lookup="java:/comp/env/jdbc/postgres")
@Resource(name="jdbc/postgres")
private DataSource dataSource;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String query = "SELECT ... FROM ..."; //here goes the query text
try(Connection connection= dataSource.getConnection();
Statement statement=connection.createStatement();
ResultSet resultSet= statement.executeQuery(query)) {
//some actions with resultSet
} catch (Exception e) {
e.printStackTrace();
}
}
}
Error code (the error line is Connection connection= dataSource.getConnection()
):
java.lang.NullPointerException
at com.nevermind.controller.TestController.doGet(TestController.java:41)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:543)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:615)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:818)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1627)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:832)
Class with InitialContext
that works fine:
public class DatabaseUtil {
public static DataSource getDataSource() {
DataSource ds=null;
try {
InitialContext cxt = new InitialContext();
ds = (DataSource) cxt.lookup( "java:/comp/env/jdbc/postgres" );
} catch (NamingException e) {
e.printStackTrace();
}
return ds;
}
}
Note: I've seen a lot of guides and similar questions, but no concrete solution.
Some answers have the similar solutions (Tomcat 7 Datasource injection mechanism), but in my case, it's still not working.
Someone said that Tomcat > 6 doesn't support @Resource
annotation (Getting null pointer exception @Resource annotation in tomcat 7), but the next answer says that it supports.
I'm confused what may be the problem ?
I was also facing the same issue.
Finally, I got the solution after two days of rigorous research.
I tried with Tomcat 7.0.104, PostgresSQL 12 and JDK 8.
Note: You can use any tomcat version and injection doesn't have anything to do with the tomcat version, you need to do proper configuration for a particular DI framework so that it can the inject external datasource like tomcat datasource.
@Bozho was right at this question : Getting null pointer exception @Resource annotation in tomcat 7
You will need dependency-injection framework to do the injection. For dependency-injection to work properly, you need to configure framework in such a way that it can find that particular resource.
Now, coming to the answer :
The things you need to update in tomcat.
context.xml :
<?xml version="1.0" encoding="UTF-8"?>
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements. See the NOTICE file distributed with this work for additional
information regarding copyright ownership. The ASF licenses this file to
You under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of
the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License. --><!-- The contents of this file will be loaded for each web application -->
<Context>
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<Resource auth="Container"
driverClassName="org.postgresql.Driver" maxActive="20" maxIdle="10"
maxWait="-1" name="jdbc/postgres" password="" type="javax.sql.DataSource"
url="jdbc:postgresql://localhost:5432/demo" username="anish" />
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!-- <Manager pathname="" /> -->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!-- <Valve className="org.apache.catalina.valves.CometConnectionManagerValve"
/> -->
</Context>
You need to update the project's web.xml (by referring to the data source that you have created in the context.xml):
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>Archetype Created Web Application</display-name>
<resource-ref>
<description>Test</description>
<res-ref-name>jdbc/postgres</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
TestController class :
package com.example;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
@WebServlet(name = "TestController", urlPatterns = "/test")
public class TestController extends HttpServlet {
private static final long serialVersionUID = 1L;
@Resource(name = "jdbc/postgres")
private DataSource dataSource;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try (Connection connection = dataSource.getConnection();) {
System.out.println(connection.getAutoCommit());
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Success Log :
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server version name: Apache Tomcat/7.0.104
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server built: May 7 2020 19:31:18 UTC
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server version number: 7.0.104.0
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: OS Name: Mac OS X
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: OS Version: 10.15.4
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Architecture: x86_64
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Java Home: /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: JVM Version: 1.8.0_231-b11
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: JVM Vendor: Oracle Corporation
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: CATALINA_BASE: /Volumes/Local Disk/STS-workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: CATALINA_HOME: /Users/anish/Downloads/apache-tomcat-7.0.104
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dcatalina.base=/Volumes/Local Disk/STS-workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dcatalina.home=/Users/anish/Downloads/apache-tomcat-7.0.104
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dwtp.deploy=/Volumes/Local Disk/STS-workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Djava.endorsed.dirs=/Users/anish/Downloads/apache-tomcat-7.0.104/endorsed
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dfile.encoding=UTF-8
Jun 26, 2020 10:10:19 AM org.apache.catalina.core.AprLifecycleListener lifecycleEvent
INFO: The Apache Tomcat Native library which allows using OpenSSL was not found on the java.library.path: [/Users/anish/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
Jun 26, 2020 10:10:19 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 413 ms
Jun 26, 2020 10:10:19 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service [Catalina]
Jun 26, 2020 10:10:19 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.104
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.TldConfig execute
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jun 26, 2020 10:10:19 AM org.apache.catalina.deploy.WebXml setVersion
WARNING: Unknown version string [3.1]. Default version will be used.
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.TldConfig execute
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jun 26, 2020 10:10:19 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.Catalina start
INFO: Server startup in 341 ms
When you access this http://localhost:8080/sample-ds-test/test
url, it will give the message true
that will denote that datasource is loaded properly.
This will work for you smoothly.
My Github repo for testing :
(Just change the database name, username, password)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With