'Using MySQL JDBC driver inside Gradle issue? [duplicate]

I am trying to learn how to use Gradle with Java and am starting a brand new project. I am trying to connect to a database.

My build.gradle file is

plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

jar {
    manifest {
        attributes 'Main-Class': 'com.brian.Application'
    }
}

dependencies {
    testImplementation 'junit:junit:4.13.2'
    implementation 'mysql:mysql-connector-java:8.0.25'
}

group 'org.brian'
version '1.0-SNAPSHOT'

File com.brian.Application is

package com.brian;

public class Application {
    public static void main(String[] args) {
        DBConnection.runDBTest();
    }
}

And my DBConnection is

package com.brian;

import java.sql.*;

public class DBConnection {
    private static String url = "jdbc:mysql://localhost:3306/RecipeCollection";
    private static String driverName = "com.mysql.cj.jdbc.Driver";
    private static String username = "RecipeCurator";
    private static String password = "Sup3rYumm!";
    private static Connection con;
    private static String urlstring;

    public static Connection getConnection() {
        try {
            Class.forName(driverName);
            try {
                con = DriverManager.getConnection(url, username, password);
            } catch (SQLException e) {
//                System.out.println("Failed to create database connection");
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            System.out.println("Could not find driver for " + driverName);
            e.printStackTrace();
        }
        return con;
    }

    public static void runDBTest() {
        Connection con = null;
        Statement stmt = null;
        ResultSet rs = null;
        con = DBConnection.getConnection();
        try {
            stmt = con.createStatement();
            rs = stmt.executeQuery("SELECT 1");
        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println("Something went wrong");
        }
        System.out.println(rs);
    }
}

When I do ./gradlew build it builds successfully.

When I try to run it with java -jar build/libs/recipe-curator-1.0-SNAPSHOT.jar I get this error

Could not find driver for com.mysql.cj.jdbc.Driver
java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:315)
    at com.brian.DBConnection.getConnection(DBConnection.java:15)
    at com.brian.DBConnection.runDBTest(DBConnection.java:33)
    at com.brian.Application.main(Application.java:5)
Exception in thread "main" java.lang.NullPointerException
    at com.brian.DBConnection.runDBTest(DBConnection.java:35)
    at com.brian.Application.main(Application.java:5)

I am not sure what is going on since I have mysql as a dependency and the build seems to work fine that this does not run. What am I doing wrong?



Solution 1:[1]

This is because Java does not know where to load the MySQL driver class from. The JAR created by your build does not have a Class-Path header that mentions the JAR files (like the MySQL Connector/J JAR) that it needs to run.

You could try and configure jar to populate Class-Path to cite the required JARs. Here is an example that works with Gradle 7.3.3

jar {
    manifest {
        attributes(
                "Main-Class": "com.brian.Application",
                'Class-Path': configurations.runtimeClasspath.files.collect { it.name }.join(' ')
        )
    }
}

This will give you Class-Path: mysql-connector-java-8.0.25.jar protobuf-java-3.11.4.jar in META-INF/MANIFEST.MF inside build/libs/recipe-curator-1.0-SNAPSHOT.jar. What it does not do is make sure that the required JARs are in the same location (build/libs).

A simpler alternative is to use Gradle's Application plugin, which helps you create a distribution that includes a runner script for Windows and Unix.

  • Add id 'application' to the plugins closure
  • Replace the jar closure with the following
application {
    mainClass.set('com.brian.Application')
}

Then just run ./gradlew build installDist. This will create tar and zip distributions under build/distributions and also install a distribution under build/install/recipe-curator. You can then run build/install/recipe-curator/bin/recipe-curator on Unix-like systems (or build\install\recipe-curator\bin\recipe-curator.bat on Windows).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 smooth reggae