Tomcat9 complaining on class not found for javax.sql.DataSource class

Viewed 2592

Tomcat9 running on a Linux based VM, startup giving following error, when a Jdk11 compiled war file is deployed in tomcat. On start of tomcat following error occurs. How to resolve this class not found exception. Is specific module java.sql to be added explicitly?

Jul 22, 2020 1:49:45 AM org.apache.catalina.startup.Catalina start
SEVERE: The required Server component failed to start so Tomcat is unable to start.
org.apache.catalina.LifecycleException: Failed to start component [StandardServer[43004]]
    at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:440)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:198)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:633)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:343)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:474)
Caused by: java.lang.NoClassDefFoundError: javax/sql/DataSource
    at java.base/java.lang.ClassLoader.findBootstrapClass(Native Method)
    at java.base/java.lang.ClassLoader.findBootstrapClassOrNull(ClassLoader.java:1258)
    at java.base/java.lang.System$2.findBootstrapClassOrNull(System.java:2131)
    at java.base/jdk.internal.loader.ClassLoaders$BootClassLoader.loadClassOrNull(ClassLoaders.java:118)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:616)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:640)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:616)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:576)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)

I have tried adding '--add-modules java.sql' in the tomcat startup script. But still no difference. Also one strange thing is that when '-verbose:module' option is added it clearly shows that module java.sql is loaded, but still ends up with NoClassDefFoundError: javax/sql/DataSource.

find /usr/lib/jvm/adoptopenjdk-11-hotspot -name java.sql.jmod -exec jar tf '{}' \; | grep DataSource
classes/javax/sql/XADataSource.class
classes/javax/sql/ConnectionPoolDataSource.class
classes/javax/sql/DataSource.class
classes/javax/sql/CommonDataSource.class

java version :

$ java -version
openjdk version "11.0.7" 2020-04-14
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.7+10)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.7+10, mixed mode)

We have following block in server.xml

<Resource
    name="jdbc/ILOraclePool"
    auth="Container"
    factory="com.xyz.tomcat.ucp.UcpDataSourceFactory" (this class extends oracle.ucp.jdbc.PoolDataSourceImpl)
    type="oracle.ucp.jdbc.PoolDataSource"
    description="main DB"
    connectionFactoryClassName="oracle.jdbc.pool.OracleDataSource"
    ....
/>
4 Answers

I think tomcat is using some other JVM. Check that.

Open catalina.sh present in tomcat9/bin directory and export JAVA_HOME.

export JAVA_HOME=/usr/lib/jvm/adoptopenjdk-11-hotspot

For the managed resources in the application servers, it is better to copy the related libs(eg. the JDBC drivers) to the application server specific libs folder(eg. the Tomcat's catalina/lib, Glassfish's domains/yourdomain/lib etc) and registered it a host/domain scope or globally in the server config file.

As I know, some JDBC drivers do not work when it is packaged into the deployable war that is deployed into Tomcat. And when using Glassfish, Wildfly, etc., I always used the server tools(UI, CLI, Maven plugin, etc.) to register JDBC/Datasource related resources in the server config.

Update: I created a new repo to demo this usage in Spring Boot, check here.

Both included an IT test on Java 11, Oracle XE 18.4.0, JNDI DataSource.

mvn verify -Pit

First ensure that Oracle JDBC jar ojdbc8.jar, ucp.jar, and ons.jar from the same version (e.g. version 12.2) are present in $CATALINA_HOME/lib. Make sure that all three jar files are from the same database version. DO NOT mix the version of these jars. Always, try to use the latest JDBC driver and UCP in order to leverage the latest capabilities and performance improvements.

Also, I recommend you change the factory class to oracle.ucp.jdbc.PoolDataSourceImpl.

Hopefully, this should resolve the problem. In case it doesn't help, please post the JNDI lookup code and the DataSource configuration in web.xml.

Have you tried moving the to context.xml ? Check out the Tomcat_Servlet code sample.

Related