JaroslavTulach: /* Modularity = */ - 2021-02-16 06:12:59

Modularity =

←Older revision Revision as of 06:12, 16 February 2021
Line 43: Line 43:
Our application has to be composed from both [[JAR]] files: ''app-jdk8.jar'' and ''app-jdk11.jar''. The entrypoint has to be in the ''app-jdk8.jar'' and it has to do something reasonable by its own when executed on [[JDK]]8. The use of '''ServiceLoader().load(BetterHandler.class)''' is going to return no ''JDK11EnhancedHandler'' (possibly yielding some {{JDK|java/lang|LinkageError}}) and as such the fallback code is executed. However when running on [[JDK11]] the ''JDK11EnhancedHandler'' is instantiated and can easily access the [[JDK11]] specific functionality.
Our application has to be composed from both [[JAR]] files: ''app-jdk8.jar'' and ''app-jdk11.jar''. The entrypoint has to be in the ''app-jdk8.jar'' and it has to do something reasonable by its own when executed on [[JDK]]8. The use of '''ServiceLoader().load(BetterHandler.class)''' is going to return no ''JDK11EnhancedHandler'' (possibly yielding some {{JDK|java/lang|LinkageError}}) and as such the fallback code is executed. However when running on [[JDK11]] the ''JDK11EnhancedHandler'' is instantiated and can easily access the [[JDK11]] specific functionality.
-
=== [[Modularity]] ====
+
=== [[Modularity]] ===
Both [[OSGi]] as well as [[NetBeans Runtime Container]] help bring this setup to even a better level. They allow one to specify in the ''app-jdk11.jar'' manifest that the [[module]] requires [[JDK11]]. E.g. when running on [[JDK]]8 the ''JDK11EnhancedHandler'' class isn't going to even be available on the "classpath". That is going to prevent any {{JDK|java/lang|LinkageError}} and just return ''null'' when the implementation of ''ServiceLoader().load(BetterHandler.class)'' is requested.
Both [[OSGi]] as well as [[NetBeans Runtime Container]] help bring this setup to even a better level. They allow one to specify in the ''app-jdk11.jar'' manifest that the [[module]] requires [[JDK11]]. E.g. when running on [[JDK]]8 the ''JDK11EnhancedHandler'' class isn't going to even be available on the "classpath". That is going to prevent any {{JDK|java/lang|LinkageError}} and just return ''null'' when the implementation of ''ServiceLoader().load(BetterHandler.class)'' is requested.

JaroslavTulach: /* Assembling the Application */ - 2021-02-16 06:12:33

Assembling the Application

←Older revision Revision as of 06:12, 16 February 2021
Line 41: Line 41:
=== Assembling the Application ===
=== Assembling the Application ===
-
Our application has to be composed from both [[JAR]] files: ''app-jdk8.jar'' and ''app-jdk11.jar''. The entrypoint has to be in the ''app-jdk8.jar'' and it has to do something reasonable by its own when executed on [[JDK]8. The use of '''ServiceLoader().load(BetterHandler.class)''' is going to return no ''JDK11EnhancedHandler'' (possibly yielding some {{JDK|java/lang|LinkageError}}) and as such the fallback code is executed. However when running on [[JDK11]] the ''JDK11EnhancedHandler'' is instantiated and can easily access the [[JDK11]] specific functionality.
+
Our application has to be composed from both [[JAR]] files: ''app-jdk8.jar'' and ''app-jdk11.jar''. The entrypoint has to be in the ''app-jdk8.jar'' and it has to do something reasonable by its own when executed on [[JDK]]8. The use of '''ServiceLoader().load(BetterHandler.class)''' is going to return no ''JDK11EnhancedHandler'' (possibly yielding some {{JDK|java/lang|LinkageError}}) and as such the fallback code is executed. However when running on [[JDK11]] the ''JDK11EnhancedHandler'' is instantiated and can easily access the [[JDK11]] specific functionality.
=== [[Modularity]] ====
=== [[Modularity]] ====

JaroslavTulach: /* Extension Point */ - 2021-02-16 06:10:37

Extension Point

←Older revision Revision as of 06:10, 16 February 2021
Line 3: Line 3:
=== Extension Point ===
=== Extension Point ===
-
When you need to access a functionality which requires different code to run on [[JDK]]8 and [[JDK11]], start by defining an [[APISeam]]:
+
When you need to access a functionality which requires some special code to be executed on [[JDK11]], start by defining an [[APISeam]]:
<source lang="java">
<source lang="java">

JaroslavTulach at 06:08, 16 February 2021 - 2021-02-16 06:08:57

←Older revision Revision as of 06:08, 16 February 2021
Line 1: Line 1:
Do you want to run [[NetBeans|your application]] on [[JDK]]8, but use [[JDK11]] [[API]]s? That's traditionally done with a reflection. Use [[JDK]]8 [[API]]s directly and let [[javac]] compile your code against them. Whenever using [[JDK11]] [[API]]s, 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 [[module]]s/[[JAR]]s and let them work in smooth orchestration.
Do you want to run [[NetBeans|your application]] on [[JDK]]8, but use [[JDK11]] [[API]]s? That's traditionally done with a reflection. Use [[JDK]]8 [[API]]s directly and let [[javac]] compile your code against them. Whenever using [[JDK11]] [[API]]s, 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 [[module]]s/[[JAR]]s and let them work in smooth orchestration.
-
=== The Integration point [[API]] ===
+
=== Extension Point ===
When you need to access a functionality which requires different code to run on [[JDK]]8 and [[JDK11]], start by defining an [[APISeam]]:
When you need to access a functionality which requires different code to run on [[JDK]]8 and [[JDK11]], start by defining an [[APISeam]]:
Line 23: Line 23:
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 [[JDK]]8 [[API]] for you - e.g. the resulting [[JAR]] is going to run on [[JDK]]8.
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 [[JDK]]8 [[API]] for you - e.g. the resulting [[JAR]] is going to run on [[JDK]]8.
 +
 +
=== Providing the Extension ===
Now let's compile the [[JDK11]] part of the application:
Now let's compile the [[JDK11]] part of the application:
Line 35: Line 37:
</source>
</source>
-
{{NB|org-openide-util-lookup|org/openide/util/lookup|ServiceProvider}} is a comfortable way to generate ''META-INF/services/BetterHandler'' registration without risk of making typos. One can of course, create the {{JDK|java/util|ServiceLoader}} registration manually.
+
{{NB|org-openide-util-lookup|org/openide/util/lookup|ServiceProvider}} is a comfortable way to generate ''META-INF/services/BetterHandler'' registration without risk of making typos. One can of course, create the {{JDK|java/util|ServiceLoader}} registration manually. This time we use '''--release 11''' flag to instruct [[JDK11]]'s [[javac]] to allow us to use all [[JDK11]]'s [[API]]s without any need to resolve to reflection.
 +
 
 +
=== Assembling the Application ===
 +
 
 +
Our application has to be composed from both [[JAR]] files: ''app-jdk8.jar'' and ''app-jdk11.jar''. The entrypoint has to be in the ''app-jdk8.jar'' and it has to do something reasonable by its own when executed on [[JDK]8. The use of '''ServiceLoader().load(BetterHandler.class)''' is going to return no ''JDK11EnhancedHandler'' (possibly yielding some {{JDK|java/lang|LinkageError}}) and as such the fallback code is executed. However when running on [[JDK11]] the ''JDK11EnhancedHandler'' is instantiated and can easily access the [[JDK11]] specific functionality.
 +
 
 +
=== [[Modularity]] ====
 +
 
 +
Both [[OSGi]] as well as [[NetBeans Runtime Container]] help bring this setup to even a better level. They allow one to specify in the ''app-jdk11.jar'' manifest that the [[module]] requires [[JDK11]]. E.g. when running on [[JDK]]8 the ''JDK11EnhancedHandler'' class isn't going to even be available on the "classpath". That is going to prevent any {{JDK|java/lang|LinkageError}} and just return ''null'' when the implementation of ''ServiceLoader().load(BetterHandler.class)'' is requested.
 +
 
 +
=== Summary ===
 +
 
 +
It is possible to write [[Java]] application that runs on [[JDK]]8 and safely use [[JDK11]] APIs without any need for reflection.

JaroslavTulach: New page: 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 comp... - 2021-02-16 05:46:42

New page: 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 comp...

New page

Do you want to run [[NetBeans|your application]] on [[JDK]]8, but use [[JDK11]] [[API]]s? That's traditionally done with a reflection. Use [[JDK]]8 [[API]]s directly and let [[javac]] compile your code against them. Whenever using [[JDK11]] [[API]]s, 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 [[module]]s/[[JAR]]s 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 [[JDK]]8 and [[JDK11]], start by defining an [[APISeam]]:

<source lang="java">
interface BetterHandler {
void handleInBetterWay();
}
</source>

and in your code locate it via [[ServiceLoader]] or [[Lookup]] library and use it:

<source lang="java">
BetterHandler h = ServiceLoader().load(BetterHandler.class);
if (h == null) {
// JDK8 default behavior
} else {
h.handleInBetterWay();
}
</source>

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 [[JDK]]8 [[API]] for you - e.g. the resulting [[JAR]] is going to run on [[JDK]]8.

Now let's compile the [[JDK11]] part of the application:

<source lang="java">
@ServiceProvider(service=BetterHandler.class)
public class JDK11EnhancedHandler implements BetterHandler {
public void handleInBetterWay() {
// directly use JDK11 APIs
}
}
</source>

{{NB|org-openide-util-lookup|org/openide/util/lookup|ServiceProvider}} is a comfortable way to generate ''META-INF/services/BetterHandler'' registration without risk of making typos. One can of course, create the {{JDK|java/util|ServiceLoader}} registration manually.