Layer Primitives (3/3): addPackage()

David M. Lloyd david.lloyd at redhat.com
Wed May 10 22:08:04 UTC 2017


Saving the controversial one for last: I'd like to re-propose adding the 
following method to the layer controller specification and 
implementation [1].

Justification:

• Existing containers and frameworks from multiple vendors and 
developers have the ability to add static and dynamic content to 
applications at run time for a variety of reasons and with a variety of 
security requirements.
• A very large number of Java users are using Java by way of such 
containers and frameworks; this functionality is generally useful.
• Containers and frameworks _will_ be using JPMS modules dynamically in 
order (at minimum) to take advantage of the security benefits provided 
thereby; the ModuleLayer.Controller API exists in recognition of this fact.
• While it is possible, via various techniques, to provide the illusion 
of adding modular content at run time by other means, these other 
techniques introduce various user-visible problems that can lead to 
undue confusion and difficulty; additionally, it would result in a 
fairly substantial increase in downstream complexity for containers, 
whereas the upstream complexity should be considerably less and can be 
utilized by all.
• The controller is only available to user-defined Layers, so there is 
no risk or exposure to the platform, jlink, etc.
• The proposed behavior is very consistent with the existing behavior of 
the module system and its implementation, and as such can be implemented 
in terms of functionality already necessarily existent in the current 
JDK codebase.
• The patch itself is very small.

Drawbacks:

• The platform would have to be specified to have the capability to 
dynamically register a package-to-module mapping for any user-managed 
Layer, which would be used for subsequent diagnostic and security 
calculations.  This is significantly mitigated by the fact that the 
reference implementation already has the required capability.  It is 
also mitigated by the fact that the implementation would not need to 
provide or support this ability for JDK-managed layer(s).
• A determination would have to be made as to whether the supplemental 
package would figure into resolver calculations; however, this should be 
mitigated by the fact that it is already possible to dynamically add 
exports.  Exporting a freshly minted package should be no different from 
exporting a previously hidden but existent package as far as it is 
concerned; the implementation seems to square with this idea.  This can 
be discussed further if some new information comes to light.
• Adding code dynamically may theoretically introduce various 
deoptimizations in the compiler (JIT) implementation.  However, adding a 
package alone should not introduce any such cases that do not already 
exist by adding classes or packages to the unnamed module, or by 
defining classes into existent packages within a module.  It is 
understood to be unlikely that the compiler would have to make any 
special consideration for this case.  This can be discussed further if 
some new information comes to light.
• The complexity and maintenance cost seems be quite low, but is not 
zero.  However, the gain to container developers, and indirectly the 
value to users thereby, should outweigh the complexity and maintenance 
cost; dynamic and self-modifying code has been a foundation capability 
of Java since the 1990s.  Enabling dynamic containers in what could be a 
substantial way, especially at such a low cost, should be considered a 
worthwhile goal that will benefit a large portion of the community. 
This can be discussed further if it is shown that the complexity or 
maintenance cost is likely to be more substantial than expected or if 
new information comes to light.


Patch information:

The content and format of the JavaDoc are drawn from neighboring 
methods.  I relinquish any copyright claim to the patch in this mail. 
Please do not get bogged down by any formatting problems introduced by 
the mailing list; the purpose of directly including the patch is to give 
a clear, unambiguous subject for discussion.  I can provide a proper 
webrev (or whatever other form is requested) if needed.  This patch 
applies atop the previous (2/3) patch, but can trivially be applied 
without it as well.

[1]:

diff --git a/jdk/src/java.base/share/classes/java/lang/Module.java 
b/jdk/src/java.base/share/classes/java/lang/Module.java
index f6ab49b..789d02f 100644
--- a/jdk/src/java.base/share/classes/java/lang/Module.java
+++ b/jdk/src/java.base/share/classes/java/lang/Module.java
@@ -1016,7 +1016,7 @@ public final class Module implements 
AnnotatedElement {
       * @throws IllegalArgumentException if the package name is not legal
       * @throws IllegalStateException if the package is defined to 
another module
       */
-    private void implAddPackage(String pn, boolean syncVM) {
+    void implAddPackage(String pn, boolean syncVM) {
          // no-op if unnamed module
          if (!isNamed())
              return;
diff --git a/jdk/src/java.base/share/classes/java/lang/ModuleLayer.java 
b/jdk/src/java.base/share/classes/java/lang/ModuleLayer.java
index 541be5f..7cb6377 100644
--- a/jdk/src/java.base/share/classes/java/lang/ModuleLayer.java
+++ b/jdk/src/java.base/share/classes/java/lang/ModuleLayer.java
@@ -332,6 +332,31 @@ public final class ModuleLayer {

              return this;
          }
+
+        /**
+         * Updates module {@code source} in the layer to contain a new 
package.
+         * This method is a no-op if {@code source} already contains 
package {@code pn}.
+         *
+         * @param  source
+         *         The source module
+         * @param  pn
+         *         The package name to add
+         *
+         * @return This controller
+         *
+         * @throws IllegalArgumentException
+         *         If {@code pn} is {@code null}, or {@code source} is 
not in the layer
+         */
+        public Controller addPackage(Module source, String pn) {
+            Objects.requireNonNull(source);
+            if (pn == null)
+                throw new IllegalArgumentException("package is null");
+            if (source.isNamed()) {
+                ensureInLayer(source);
+                source.implAddPackage(pn, true);
+            }
+            return this;
+        }
      }



-- 
- DML


More information about the jpms-spec-experts mailing list