26

I'm trying to add a JDBC connector module to my project with Java 11. I downloaded the MSSqlServer JDBC driver 7.2 for Java 11

https://www.microsoft.com/en-us/download/details.aspx?id=57782

I added the module :

requires com.microsoft.sqlserver.jdbc;

Yet when I try to clean+build, NetBeans tells me:

Error: automatic module cannot be used with jlink: com.microsoft.sqlserver.jdbc from file: /sqljdbc_7.2/enu/mssql-jdbc-7.2.2.jre11.jar

I'm pretty sure this is because the jar doesn't have a compiled module-info.java. However, I was wondering if there is a way to inject one in there?

trilogy
  • 1,738
  • 15
  • 31
  • 1
    You can use `jdeps` to generate a `module-info.java` file then [compile it](https://stackoverflow.com/questions/47222226/how-to-inject-module-declaration-into-jar). Then you just need to add `module-info.class` to the JAR file, I believe. – Slaw Jun 19 '19 at 04:29
  • 5
    @Slaw this is a real pain. There are so many dependencies that will need to be modularized as well... Is there a way to use jlink to create a custom runtime but include extra legacy jars with the runtime outside ? – trilogy Jun 19 '19 at 14:39
  • Not with `jlink`. If you're using Maven you might be able to use [this plugin](https://github.com/moditect/moditect). Looks like they also have [a plugin](https://github.com/moditect/moditect-gradle-plugin/) for Gradle. You could also try [`jpackage`](https://jdk.java.net/jpackage/), though it's currently early-access and based on JDK 13. From my one-time experience with that tool it allows you to mix the modulepath/classpath _or_ explicit/automatic modules. However, unlike `jlink`, the `jpackage` tool provides zero support for cross-platform packaging. – Slaw Jun 19 '19 at 15:04
  • Note when I say, "_mix the modulepath/classpath or explicit/automatic modules_", I really do mean either-or. If your code is modular, and you want to use it on the modulepath, then everything needs to be on the modulepath. This is because explicit modules don't have access to the classpath (i.e. the "unnamed module"). The dependencies on the modulepath don't have to be explicit modules, however; they can be automatic modules. If your code is non-modular, then you can have stuff on the modulepath and your code on the classpath (you'll probably have to use `--add-modules` though). – Slaw Jun 19 '19 at 15:09
  • 2
    I think it is impossible to find any serious project that won't have modules with automatic module names, for example spring has them. So, jlink we can use only to create custom jre but not to link our project modules. – Pavel_K Nov 25 '20 at 19:07
  • Try using the gradle badass jlink plugin. It creates all the necessary module-info's if they are missing. Pretty fancy :) https://badass-jlink-plugin.beryx.org/ – schwaller Dec 19 '22 at 23:14
  • Try to find a version of the SQL Server JDBC driver that is packaged as a Java module, or you could use a different tool to create a custom runtime image, such as jdeps or the jlink plugin for Gradle or Maven. – Shaik Feb 03 '23 at 18:37

1 Answers1

1

If you are using Maven, you can use the add-module-info goal of the moditect plugin. Below is a snippet of pom.xml I used to make the h2 jdbc driver and engine work with jlink. The plugin creates a patched copy of the plugin in ${project.build.directory}/modules which can then be jlinked in. I had to create the moduleInfoSource section myself. To do that I used jdeps --multi-release=11, java --describe-module and the moditect:generate-module-info goal and examining the manifest file to work out the requires statements etc. - for these to work you have to include all the dependencies of the JDBC jar you are trying to jlink. H2 has a lot of 'optional' features - I had to manually mark the requires for those as static. All this is pretty tedious, but if you do the same for the SQL Server JDBC driver, it should work for future releases, until an official modular component is released:

<plugin>
    <artifactId>maven-jlink-plugin</artifactId>
    <version>3.1.0</version>
    <extensions>true</extensions>
    <configuration>
        <launcher>myapp=myappmodule/mypackage.MainClass</launcher>
        <modulePaths>
           <modulePath>${project.build.directory}/modules</modulePath>
        </modulePaths>
    </configuration>
</plugin>

<plugin>
    <groupId>org.moditect</groupId>
    <artifactId>moditect-maven-plugin</artifactId>
    <version>1.0.0.RC2</version>
    <executions>
        <execution>
            <id>add-module-infos</id>
            <phase>generate-resources</phase>
            <goals>
                <goal>add-module-info</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/modules</outputDirectory>
                <modules>
                    <module>
                        <artifact>
                            <groupId>com.h2database</groupId>
                            <artifactId>h2</artifactId>
                            <version>2.1.214</version>
                        </artifact>
                        <moduleInfoSource>
                            module com.h2database {
                            requires java.compiler;
                            requires jdk.net;
                            requires static lucene.core;
                            requires static lucene.queryparser;
                            requires static slf4j.api;
                            requires static jakarta.servlet;
                            requires transitive java.desktop;
                            requires transitive java.instrument;
                            requires java.logging;
                            requires transitive java.management;
                            requires static java.naming;
                            requires transitive java.scripting;
                            requires java.sql;
                            requires transitive java.transaction.xa;
                            requires transitive java.xml;
                            requires static javax.servlet.api;
                            requires static org.locationtech.jts;
                            requires static org.osgi.service.jdbc;
                            requires static osgi.core;
                            provides java.sql.Driver with org.h2.Driver;
                            }
                        </moduleInfoSource>
                    </module>
                </modules>
            </configuration>
        </execution>
    </executions>
</plugin>