AlternativeImplementation
From APIDesign
Do you want to run your application on JDK8, but use JDK11 APIs? That's traditionally done with a reflection. Use JDK8 APIs directly and let javac compile your code against them. Whenever using JDK11 APIs, resort to reflection and call them in such a verbose, unsafe manner. That's indeed possible, but especially with modularity one has better option. Create few modules/JARs and let them work in smooth orchestration.
The Integration point API
When you need to access a functionality which requires different code to run on JDK8 and JDK11, start by defining an APISeam:
interface BetterHandler { void handleInBetterWay(); }
and in your code locate it via ServiceLoader or Lookup library and use it:
BetterHandler h = ServiceLoader().load(BetterHandler.class); if (h == null) { // JDK8 default behavior } else { h.handleInBetterWay(); }
Compile these pieces of code to run on JDK8. Btw. that can easily be done with JDK11 javac - just use the --release 8 - flag. Then the javac is only going to expose JDK8 API for you - e.g. the resulting JAR is going to run on JDK8.
Now let's compile the JDK11 part of the application:
@ServiceProvider(service=BetterHandler.class) public class JDK11EnhancedHandler implements BetterHandler { public void handleInBetterWay() { // directly use JDK11 APIs } }
ServiceProvider is a comfortable way to generate META-INF/services/BetterHandler registration without risk of making typos. One can of course, create the ServiceLoader registration manually.