Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No suitable drivers available when deploying a Spring 6 war to Tomcat 10

I have not used this traditional way to deploy wars to a tomcat in the past years.

In these days, I tried to update myself to Spring 6/Jakarta EE 9/Java 17 and created a simple example to demo a Spring WebMvc war application, when deploying to a Tomcat 10 via cargo maven plugin or manually , I got the famous no suitable drivers at the application startup stage when hibernate is initialized.

But it worked in unit tests.

I've also tried to deploy to an external Tomcat server, firstly copy a postgres jar to the tomcat/lib folder, and then copy the war package to the tomcat/webapps folder, and start it manually, but got the same errors.

My example project: https://github.com/hantsy/spring6-sandbox/tree/master/jpa , based on the following tech stack:

  • Jakarta EE 9/Java 17
  • Spring 6.0.0-M1
  • Hibernate 5.6 jakarta variants/Postgres Jdbc Driver 42.3.1
  • Apache Tomcat 10.0.14

To reproduce the issues, start Postgres via docker compose up postgres and run mvn clean package cargo:run -Ptomcat in the project folder to deploy to the cargo managed tomcat server.

PS: I also configured Jetty and WildFly, both worked well.

Update: This issue is a little weird, because packaging Postgres jdbc driver into war worked well with Spring5/Tomcat9. But it failed in this sample which upgraded to Spring6/Tomcat10. To make it work, I have to exclude the pg Jdbc driver from the war package, and copy it to the common tomcat/lib folder, see the integration tests for more details. More about the Jdbc driver loading see @PiotrP.Karwasz's answer.

BTW, Tomcat was the preferred web server for Java developers, one reason was most of the popular Jdbc drivers worked well when packaging it into wars,in contrast most of the traditional application servers(WildFly, Glassfish, etc) did not support it in the past years(you have to install it to application server via the application server command line tools or admin console). But since Java EE 7, it allows developers to define application-scoped DataSources(via @DataSourceDefinition) and package Jdbc drivers into the application war packages directly, when the application is being deployed, it will register the Jdbc drivers automatically. Not sure why the newest Tomcat increases the development complexity and uses the legacy application server approach.

like image 677
Hantsy Avatar asked Dec 06 '25 02:12

Hantsy


1 Answers

Short answer: in your DataSourceConfig class you don't call DriverManagerDataSource#setDriverClassName, hence the DriverManager does not know where to find a suitable driver for a jdbc:postgresql: URI.

Long answer: wait, do I really need to specify the driver's class name, aren't JDBC drivers autodetected? Yes, since Java 6 and JDBC 4, JDBC drivers are automatically detected through the ServiceLoader mechanism.

However this happens only once during the first call to DriverManager.getDrivers(). Tomcat makes sure this happens from the server's classpath (cf. JreMemoryLeakPrevention), so only the drivers installed globally are registered (no references to application classloaders are held by the system classloader).

Therefore, instead of specifying the driver's class name, you can:

  • either install the PostgreSQL JDBC driver in the server's classpath (e.g. $CATALINA_BASE/lib) and remove it from the application,
  • or make sure the driver is loaded when your application starts (and deregistered when it stops):
    Class.forName("org.postgresql.Driver");
    
  • you can also emulate the auto-discovery mechanism used by DriverManager to register all the drivers distributed with your application:
     private static void registerJdbcDrivers(ServletContext context) {
         final ServiceLoader<Driver> serviceLoader = ServiceLoader.load(Driver.class, context.getClassLoader());
         final Iterator<Driver> iter = serviceLoader.iterator();
         while (iter.hasNext()) {
             // Just for the side-effect of loading the class and registering the driver
             iter.next();
         }
     }
    
like image 177
Piotr P. Karwasz Avatar answered Dec 08 '25 21:12

Piotr P. Karwasz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!