Finally managed to reproduce it in a test: https://github.com/apache/tomcat/pull/183
Romain Manni-Bucau @rmannibucau <https://twitter.com/rmannibucau> | Blog <https://rmannibucau.metawerx.net/> | Old Blog <http://rmannibucau.wordpress.com> | Github <https://github.com/rmannibucau> | LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book <https://www.packtpub.com/application-development/java-ee-8-high-performance> Le mar. 30 juil. 2019 à 14:21, Romain Manni-Bucau <rmannibu...@gmail.com> a écrit : > Yes, got caught by PooledConnection.class.getClassLoader() which tries to > load the driver from tomcat/lib first (common.loader actually) so if you > put your driver there it will work in your case. Stays the bug when the > driver is only in the webapp. > > > Romain Manni-Bucau > @rmannibucau <https://twitter.com/rmannibucau> | Blog > <https://rmannibucau.metawerx.net/> | Old Blog > <http://rmannibucau.wordpress.com> | Github > <https://github.com/rmannibucau> | LinkedIn > <https://www.linkedin.com/in/rmannibucau> | Book > <https://www.packtpub.com/application-development/java-ee-8-high-performance> > > > Le mar. 30 juil. 2019 à 13:30, Clemens Wyss DEV <clemens...@mysign.ch> a > écrit : > >> > recent tomcat version >> >> 9.0.22 has the same class loading code as 8.5.35 >> >> >> https://jar-download.com/artifacts/org.apache.tomcat/tomcat-jdbc/9.0.22/source-code/org/apache/tomcat/jdbc/pool/PooledConnection.java >> >> driver = (java.sql.Driver) >> >> ClassLoaderUtil.*loadClass*( >> >> poolProperties.getDriverClassName(), >> >> PooledConnection.*class*.getClassLoader(), >> >> Thread.*currentThread* >> ().getContextClassLoader() >> >> ).getConstructor().newInstance(); >> >> >> >> >> >> *Von:* Romain Manni-Bucau <rmannibu...@gmail.com> >> *Gesendet:* Montag, 29. Juli 2019 09:35 >> *An:* Tomcat Developers List <dev@tomcat.apache.org> >> *Betreff:* Re: PooledConnection#connectUsingDriver, >> Thread.currentThread().getContextClassLoader() is null >> >> >> >> Can you give a try on a more recent tomcat version? Seems it works with >> master version since the tomcat-jdbc module classloader is tried first >> before the tccl? >> >> Tested with: >> >> >> >> *public class *PooledConnectionTest { >> @Test >> *public void *avoidNPEWhenTcclIsNull() *throws *SQLException { >> *final *PoolProperties poolProperties = *new *PoolProperties(); >> poolProperties.setDriverClassName(*"org.h2.Driver"*); >> poolProperties.setUsername(*"sa"*); >> poolProperties.setPassword(*""*); >> >> poolProperties.setUrl(*"jdbc:h2:mem:PooledConnectionTest_avoidNPEWhenTcclIsNull"*); >> poolProperties.setMaxIdle(1); >> poolProperties.setMinIdle(1); >> poolProperties.setInitialSize(1); >> poolProperties.setMaxActive(1); >> >> ensureDataSourceIsValid(poolProperties); >> >> *final *Thread thread = Thread.*currentThread*(); >> *final *ClassLoader testLoader = thread.getContextClassLoader(); >> thread.setContextClassLoader(*null*); >> *try *{ >> ensureDataSourceIsValid(poolProperties); >> } *finally *{ >> thread.setContextClassLoader(testLoader); >> } >> } >> >> *private void *ensureDataSourceIsValid(*final *PoolProperties >> poolProperties) *throws *SQLException { >> *final *DataSource dataSource = *new *DataSource(poolProperties); >> *try *(*final *Connection connection = dataSource.getConnection()) { >> *assertTrue*(connection.isValid(5)); >> } *finally *{ >> dataSource.close(); >> } >> } >> } >> >> >> Romain Manni-Bucau >> @rmannibucau <https://twitter.com/rmannibucau> | Blog >> <https://rmannibucau.metawerx.net/> | Old Blog >> <http://rmannibucau.wordpress.com> | Github >> <https://github.com/rmannibucau> | LinkedIn >> <https://www.linkedin.com/in/rmannibucau> | Book >> <https://www.packtpub.com/application-development/java-ee-8-high-performance> >> >> >> >> >> >> Le lun. 29 juil. 2019 à 07:36, Clemens Wyss DEV <clemens...@mysign.ch> a >> écrit : >> >> https://bz.apache.org/bugzilla/show_bug.cgi?id=63612 >> >> >> > with a small project reproducing it? >> >> Unfortunately not easily extractable/reproducible >> >> Maybe : >> >> th = new Thread() { >> @Override >> >> public void run() { >> « do something that requires a connection from the pool » >> >> } >> } ; >> th.set getContextClassLoader( null ) ; >> th.run() ; >> >> >> >> *Von:* Romain Manni-Bucau <rmannibu...@gmail.com> >> *Gesendet:* Donnerstag, 25. Juli 2019 08:06 >> *An:* Tomcat Developers List <dev@tomcat.apache.org> >> *Betreff:* Re: PooledConnection#connectUsingDriver, >> Thread.currentThread().getContextClassLoader() is null >> >> >> >> >> >> Le jeu. 25 juil. 2019 à 07:46, Clemens Wyss DEV <clemens...@mysign.ch> a >> écrit : >> >> < mais c'était rapide 😉 > >> >+1 >> should/can I file a bug? >> >> >> >> Guess so, with a small project reproducing it? >> >> >> >> >> > init at bootstrap the pool (initial size) to ensure it is in one tomcat >> classloader >> how would you achieve this? By setting «initialSize» to «maxSize» in >> PoolProperties? >> >> >> >> 1 should be sufficient, however tomcat-jdbc (vs dbcp2 for instance) loads >> it per connection and not once for all the pool ( >> https://github.com/apache/tomcat/blob/master/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java#L196) >> which is likely 1. Bad for perf but moreover 2. Buggy if the classloader >> changes between usages of a connection in apps. Loader, driver should be >> loaded once and potentially the datasource be duplicated per app if needed >> (driver in the app) IMHO. This would also fix your NPE transitively ;). >> >> >> >> >> >> >> >> >> ---------------------------------------------------------- >> Von: Romain Manni-Bucau <rmannibu...@gmail.com> >> Gesendet: Donnerstag, 25. Juli 2019 07:30 >> An: Tomcat Developers List <dev@tomcat.apache.org> >> Betreff: Re: PooledConnection#connectUsingDriver, >> Thread.currentThread().getContextClassLoader() is null >> >> +1, there is no real other option AFAIK until you init at bootstrap the >> pool (initial size) to ensure it is in one tomcat classloader. >> >> Le jeu. 25 juil. 2019 à 07:08, Clemens Wyss DEV <mailto: >> clemens...@mysign.ch> a écrit : >> I tried posting this in the tomcat-users-ml, but I guess it rather fits >> here: >> ---------------------------------------------------------- >> Context: >> Debian GNU/Linux 9 \n \l >> java version 1.8.0_162 >> Tomcat 8.5.35 >> >> From time to time we are facing the follwing exception (call stack): >> ... >> Caused by: java.sql.SQLException: Unable to load class: >> org.mariadb.jdbc.Driver from ClassLoader:http://java.net >> .URLClassLoader@4c873330;ClassLoader:null >> at >> org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:292) >> at >> org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:212) >> at >> org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:736) >> at >> org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:668) >> at >> org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:198) >> at >> org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:132) >> at org.apache.torque.Torque.getConnection(Torque.java:924) >> ... 53 common frames omitted >> Caused by: java.lang.ClassNotFoundException: Unable to load class: >> org.mariadb.jdbc.Driver from ClassLoader:http://java.net >> .URLClassLoader@4c873330;ClassLoader:null >> at >> org.apache.tomcat.jdbc.pool.ClassLoaderUtil.loadClass(ClassLoaderUtil.java:56) >> at >> org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:280) >> ... 59 common frames omitted >> Caused by: java.lang.ClassNotFoundException: Classloader is null >> at >> org.apache.tomcat.jdbc.pool.ClassLoaderUtil.loadClass(ClassLoaderUtil.java:40) >> ... 60 common frames omitted >> >> According to the code (in PooledConnection# connectUsingDriver) >> Thread.currentThread().getContextClassLoader() returns null >> >> Googling for " Thread.currentThread().getContextClassLoader() is null" >> the common demoniator seems to be `getContextClassLoader can be null`. If >> this is true there should be >> a) a null-check in PooledConnection# connectUsingDriver >> b) if null, then there should be a fallback-Classloader (the system class >> laoder?) >> >> WDYT ? >> >> Or any ideas why the given exception pops up from time to time >> >> Thx >> Clemens >> >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: mailto:dev-unsubscr...@tomcat.apache.org >> For additional commands, e-mail: mailto:dev-h...@tomcat.apache.org >> >>