Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selectively using third-party implementation for deprecated JavaEE modules

I am currently porting an open source library to be JDK9+ compliant, and it depends on some of the Java EE Modules that have been deprecated in Java 9 and removed in Java 11: specifically, JAXB, JAX-WS and javax.annotation.

I added explicit dependencies to the third party implementations as suggested here:

<dependency>
  <groupId>com.sun.xml.ws</groupId>
  <artifactId>jaxws-ri</artifactId>
  <version>2.3.0.1</version>
</dependency>
<dependency>
  <groupId>com.sun.xml.bind</groupId>
  <artifactId>jaxb-ri</artifactId>
  <version>2.3.0.1</version>
</dependency>
<dependency>
  <groupId>com.sun.activation</groupId>
  <artifactId>javax.activation</artifactId>
  <version>1.2.0</version>
</dependency>

However, I'd like my library to use them only if necessary (i.e., on JDK9+) and keep using the endorsed implementations on JDK8.

I can do so by adding the dependencies in a Maven profile to be activated only on JDK 9 and above, but what if I wanted to publish the jar file for my library on Maven Central? Should I publish two different jars, one with the Java EE third party implementations included, for JDK9+ and one without for JDK8?

Is there a way to produce a jar file that will use the third party implementations on JDK9+ and the endorsed ones on JDK8?

I have looked into multi-release jars, but looks like they are intended for jdk version-dependent implementations among project classes, not among dependencies.

Also, in case it's not possible to use the endorsed implementations on JDK 8, is there a way to reliably test that using the third party implementations does not introduce any regressions?

like image 736
Raibaz Avatar asked Nov 06 '22 22:11

Raibaz


1 Answers

Is there a way to produce a jar file that will use the third party implementations on JDK9+ and the endorsed ones on JDK8?

Unfortunately, no. When distributing a library via jar file, you cannot control how other jars and libraries will be listed in the classpath. This makes class loading non-deterministic for you. What that means for your situation is that if the aforementioned libraries are included in the classpath in a JDK8 environment, there is no way to determine or control which version of the classes get loaded.

Also, in case it's not possible to use the endorsed implementations on JDK 8, is there a way to reliably test that using the third party implementations does not introduce any regressions?

As the author, it would be up to you to execute tests across the different runtime environments to check for regressions.

Should I publish two different jars, one with the Java EE third party implementations included, for JDK9+ and one without for JDK8?

This is a perfectly reasonable solution which others have used before as well. Take for example the sqlserver jdbc jars, which have different versions based on jre: https://learn.microsoft.com/en-us/sql/connect/jdbc/using-the-jdbc-driver?view=sql-server-2017 For the case described here, the JDK9+ version of the jar could declare the additional dependencies you mentioned in the question, whereas the JDK8 version would not.

One other option would be to have a single jar and to declare the dependecies you mentioned as provided. This would signal to the consumer that the runtime environment must include the classes in the declared dependencies. Some documentation would be called for to direct the consumer of the library as to when to they must explicitly add the jars declared as provided to their classpath.

IMHO, the clearest solution is two jars with a reference to the JRE version in the jar name and differing dependencies. It requires very little documentation (which most dont look at anyway). And it allows you to make changes in your library more freely.

like image 84
John Camerin Avatar answered Nov 15 '22 10:11

John Camerin