3

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"
    ....
/>
YS_NE
  • 194
  • 2
  • 21
  • 1
    I understand that the tag in server.xml file is causing javax.sql.DataSource to be loaded or looking for it. If I dont have this tag, then later on this class is getting loaded fine. but certainly will be other issues. So is there a way to load this class javax.sql.DataSource by the time server.xml is getting processed? – YS_NE Jul 31 '20 at 14:19

4 Answers4

2

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
Anish B.
  • 9,111
  • 3
  • 21
  • 41
  • @24_Jogi Is this helpful – Anish B. Aug 01 '20 at 05:57
  • No interestingly, if I remove the tag from server.xml then it goes further and also eventually load the javax.sql.DataSource class also. But then I actually must have tag to initialize the db connection etc.. But tomcat using another java, that is not possible, because it does load other classes e.g. from java.base module. So there is only one java installed which supports modules. – YS_NE Aug 04 '20 at 01:28
2

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
Hantsy
  • 8,006
  • 7
  • 64
  • 109
  • Yes right. I already have oracle driver jars in tomcat lib (ucp.jar, ojdbc8.jar, ons.jar, oraclepki.jar, simplefan.jar, aspectjweaver.jar) – YS_NE Aug 04 '20 at 01:34
  • 1
    @24_Jogi Still no luck? Personally I have not used oracle and standalone tomcats in these years. But I have verified this combination(oracle 18+java 11+tomcat 9) myself yesterday, all work as expected. I will share my sample soon. – Hantsy Aug 12 '20 at 03:58
  • Didnt update in time. But this was resolved. This seemed a side effect of something in setenv.sh script. The script had various argument and one of the statement was a javaagent which was to access some component which was not accessible from this VM. So the error was completely a side effect, not directly related. But I wished there should have been a better error message. – YS_NE Sep 09 '22 at 03:23
2

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.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • I have verified that oracle driver jars are from same version 12.2.0.1 and the latest ojdbc8 [https://www.oracle.com/database/technologies/jdbc-ucp-122-downloads.html] available. About replacing the factory class, we have a custom class which extends the same PoolDataSourceImpl just overriding getObjectInstance method to meet our custom needs, which worked fine with Tomcat8+Jdk8. Actually I did try that, replacing with PoolDataSourceImpl, but still same problem, NoClassDefFoundError : javax/sql/DataSource. – YS_NE Aug 04 '20 at 17:35
0

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

Nirmala
  • 1,278
  • 1
  • 10
  • 11