Warning: Using the jpackage
tool may make it more complicated to deploy your application, as the tool can only create executables/installers for the operating system it's executing on.
The jlink
tool only works with explicit modules. In other words, the module must have a module-info
descriptor. So, you cannot include the MySQL JDBC driver in the run-time image, because that library is not modular. You could try to "hack" the dependency to make it modular, but that can be difficult and error prone.
That said, the jpackage
tool works with modular and non-modular applications. This is important in this case, because JDBC drivers are service providers, meaning named modules can load them via the service-loader mechanism even if the provider is in the unnamed module. In order to include the MySQL JDBC driver with your code, configure jpackage
to put all needed explicit modules in a custom run-time image (it uses jlink
behind the scenes), and then put the driver on the class-path via the --input
option.
Example
Here's a very basic example showing what I described above. Note all tool invocations in this example are executed directly on the command line rather than via an IDE or a build tool.
The example does not include JavaFX as it's not important to what's being demonstrated.
Source Code
module-info:
module sample {
requires java.sql;
}
sample.Main:
package sample;
import java.sql.DriverManager;
public class Main {
public static void main(String[] args) throws Exception {
try (var con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test")) {
System.out.println("Made connection!");
}
}
}
Project Layout
C:\...\PROJECT
│
├───lib
│ mysql-connector-j-8.0.33.jar
│
└───src
└───sample
│ module-info.java
│
└───sample
Main.java
Creating Executable
First compile the project:
javac --module-source-path src --module sample -d out/modules
Then package the application:
jpackage --type app-image --name TestApp --module-path out/modules --add-modules java.naming --module sample/sample.Main --input lib --dest out --win-console
Couple notes:
I included --win-console
because I wanted to see the console output when running the executable (and I'm on Windows).
I included --add-modules java.naming
because it appears the MySQL JDBC driver requires that module to run. You may or may not find you need to include more modules; if you do, simply add them to the --add-modules
argument or, if it makes more sense, add appropriate requires
directives to your code's module-info descriptor.
Running Executable
I do not currently have a MySQL server available for testing, so the output I show below is an exception stack trace. But if you look at the exception, you'll see the error is that a connection could not be made. That fact, plus the fact that MySQL JDBC driver code shows up in the stack trace, shows that the MySQL JDBC driver was found successfully.
The command (Windows):
.\out\TestApp\TestApp.exe
The output (with no running MySQL server):
Exception in thread "main" com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:175)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:825)
at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:446)
at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:239)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:188)
at java.sql/java.sql.DriverManager.getConnection(Unknown Source)
at java.sql/java.sql.DriverManager.getConnection(Unknown Source)
at sample/sample.Main.main(Unknown Source)
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(Unknown Source)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Unknown Source)
at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:62)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:150)
at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:166)
at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:89)
at com.mysql.cj.NativeSession.connect(NativeSession.java:121)
at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:945)
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:815)
... 6 more
Caused by: java.net.ConnectException: Connection refused: connect
at java.base/sun.nio.ch.Net.connect0(Native Method)
at java.base/sun.nio.ch.Net.connect(Unknown Source)
at java.base/sun.nio.ch.Net.connect(Unknown Source)
at java.base/sun.nio.ch.NioSocketImpl.connect(Unknown Source)
at java.base/java.net.SocksSocketImpl.connect(Unknown Source)
at java.base/java.net.Socket.connect(Unknown Source)
at com.mysql.cj.protocol.StandardSocketFactory.connect(StandardSocketFactory.java:153)
at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:63)
... 9 more
Failed to launch JVM
Application Layout
Here's the layout of the application generated by the above jpackage
command:
C:\...\PROJECT\OUT\TESTAPP
│ TestApp.exe
│
├───app
│ .jpackage.xml
│ mysql-connector-j-8.0.33.jar
│ TestApp.cfg
│
└───runtime
│ release
│
├───bin
│ │ api-ms-win-core-console-l1-1-0.dll
│ │ api-ms-win-core-console-l1-2-0.dll
│ │ api-ms-win-core-datetime-l1-1-0.dll
│ │ api-ms-win-core-debug-l1-1-0.dll
│ │ api-ms-win-core-errorhandling-l1-1-0.dll
│ │ api-ms-win-core-fibers-l1-1-0.dll
│ │ api-ms-win-core-file-l1-1-0.dll
│ │ api-ms-win-core-file-l1-2-0.dll
│ │ api-ms-win-core-file-l2-1-0.dll
│ │ api-ms-win-core-handle-l1-1-0.dll
│ │ api-ms-win-core-heap-l1-1-0.dll
│ │ api-ms-win-core-interlocked-l1-1-0.dll
│ │ api-ms-win-core-libraryloader-l1-1-0.dll
│ │ api-ms-win-core-localization-l1-2-0.dll
│ │ api-ms-win-core-memory-l1-1-0.dll
│ │ api-ms-win-core-namedpipe-l1-1-0.dll
│ │ api-ms-win-core-processenvironment-l1-1-0.dll
│ │ api-ms-win-core-processthreads-l1-1-0.dll
│ │ api-ms-win-core-processthreads-l1-1-1.dll
│ │ api-ms-win-core-profile-l1-1-0.dll
│ │ api-ms-win-core-rtlsupport-l1-1-0.dll
│ │ api-ms-win-core-string-l1-1-0.dll
│ │ api-ms-win-core-synch-l1-1-0.dll
│ │ api-ms-win-core-synch-l1-2-0.dll
│ │ api-ms-win-core-sysinfo-l1-1-0.dll
│ │ api-ms-win-core-timezone-l1-1-0.dll
│ │ api-ms-win-core-util-l1-1-0.dll
│ │ api-ms-win-crt-conio-l1-1-0.dll
│ │ api-ms-win-crt-convert-l1-1-0.dll
│ │ api-ms-win-crt-environment-l1-1-0.dll
│ │ api-ms-win-crt-filesystem-l1-1-0.dll
│ │ api-ms-win-crt-heap-l1-1-0.dll
│ │ api-ms-win-crt-locale-l1-1-0.dll
│ │ api-ms-win-crt-math-l1-1-0.dll
│ │ api-ms-win-crt-multibyte-l1-1-0.dll
│ │ api-ms-win-crt-private-l1-1-0.dll
│ │ api-ms-win-crt-process-l1-1-0.dll
│ │ api-ms-win-crt-runtime-l1-1-0.dll
│ │ api-ms-win-crt-stdio-l1-1-0.dll
│ │ api-ms-win-crt-string-l1-1-0.dll
│ │ api-ms-win-crt-time-l1-1-0.dll
│ │ api-ms-win-crt-utility-l1-1-0.dll
│ │ java.dll
│ │ jimage.dll
│ │ jli.dll
│ │ msvcp140.dll
│ │ net.dll
│ │ nio.dll
│ │ syslookup.dll
│ │ ucrtbase.dll
│ │ vcruntime140.dll
│ │ vcruntime140_1.dll
│ │ verify.dll
│ │ zip.dll
│ │
│ ├───client
│ │ jvm.dll
│ │
│ └───server
│ jvm.dll
│
├───conf
│ │ logging.properties
│ │ net.properties
│ │
│ └───security
│ │ java.policy
│ │ java.security
│ │
│ └───policy
│ │ README.txt
│ │
│ ├───limited
│ │ default_local.policy
│ │ default_US_export.policy
│ │ exempt_local.policy
│ │
│ └───unlimited
│ default_local.policy
│ default_US_export.policy
│
├───legal
│ ├───java.base
│ │ ADDITIONAL_LICENSE_INFO
│ │ aes.md
│ │ asm.md
│ │ ASSEMBLY_EXCEPTION
│ │ c-libutl.md
│ │ cldr.md
│ │ icu.md
│ │ LICENSE
│ │ public_suffix.md
│ │ unicode.md
│ │ wepoll.md
│ │ zlib.md
│ │
│ ├───java.logging
│ │ ADDITIONAL_LICENSE_INFO
│ │ ASSEMBLY_EXCEPTION
│ │ LICENSE
│ │
│ ├───java.naming
│ │ ADDITIONAL_LICENSE_INFO
│ │ ASSEMBLY_EXCEPTION
│ │ LICENSE
│ │
│ ├───java.security.sasl
│ │ ADDITIONAL_LICENSE_INFO
│ │ ASSEMBLY_EXCEPTION
│ │ LICENSE
│ │
│ ├───java.sql
│ │ ADDITIONAL_LICENSE_INFO
│ │ ASSEMBLY_EXCEPTION
│ │ LICENSE
│ │
│ ├───java.transaction.xa
│ │ ADDITIONAL_LICENSE_INFO
│ │ ASSEMBLY_EXCEPTION
│ │ LICENSE
│ │
│ └───java.xml
│ ADDITIONAL_LICENSE_INFO
│ ASSEMBLY_EXCEPTION
│ bcel.md
│ dom.md
│ jcup.md
│ LICENSE
│ xalan.md
│ xerces.md
│
└───lib
│ classlist
│ jrt-fs.jar
│ jvm.cfg
│ jvm.lib
│ modules
│ tzdb.dat
│ tzmappings
│
└───security
blocked.certs
cacerts
default.policy
public_suffix_list.dat