JDK-8341865 : Implement Module Import Declarations (Second Preview)
  • Type: CSR
  • Component: tools
  • Sub-Component: javac
  • Priority: P4
  • Status: Finalized
  • Resolution: Unresolved
  • Fix Versions: 24
  • Submitted: 2024-10-09
  • Updated: 2024-11-01
Related Reports
CSR :  
Description
Summary
-------

Based on the experiences with the previous round of preview, we propose the following updates to this feature:

 - `requires transitive java.base;` will be permitted,
 - the `java.se` module will be enhanced to include `requires transitive java.base;`,
 - types imported using a module import will be shadowed by types imported using on-demand imports, in addition to being shadowed by single-element imports.

The module imports feature will re-preview.

Problem
-------

During the previous round of preview, two issues have been identified:

First, doing `import module java.se;` imports all Java SE packages, except for packages from the `java.base` module. This seems confusing and unexpected, as users may rightfully expect that `import module java.se;` will import all types from `java.base`. (Please see https://mail.openjdk.org/pipermail/amber-spec-experts/2024-July/004184.html)

Second, having code like:

    import module java.base;
    import module java.desktop;
    ...
    List l; //ambiguous

the only way to disambiguate was either to use a single-element import (i.e. `import java.util.List;`) or a fully-qualified name. This seems to be too restricted. (Please see https://bugs.openjdk.org/browse/JDK-8341289)

Solution
--------

To solve the first problem, two changes are proposed:

 - `requires transitive java.base;` will be permitted. This is currently not permitted for classfiles version 54 and later. This sub-feature will also be covered by the preview handling, i.e. general classfiles using this feature will be marked as preview classfiles.
 - the module-info for the `java.se` module will be enhanced to include `requires transitive java.base;`. The `java.se` module specifically, and any other `java.*` module will be considered to be participating in preview with regards to this sub-feature, and will not be marked as a preview classfile.

To solve the second problem the following is proposed: types imported using a module import will be shadowed by types imported using on-demand imports, in addition to being shadowed by single-element imports.

As a consequence, to solve the above ambiguity problem, one can write:

    import module java.base;
    import module java.desktop;
    import java.util.*;
    ...
    List l; //not-ambiguous


Specification
-------------

The definition of the `java.se` module is enhanced as follows:

    diff --git a/src/java.se/share/classes/module-info.java b/src/java.se/share/classes/module-info.java
    index 81b1bd3cb8aa9..9a2704660b7b9 100644
    --- a/src/java.se/share/classes/module-info.java
    +++ b/src/java.se/share/classes/module-info.java
    @@ -23,6 +23,8 @@
      * questions.
      */

    +import jdk.internal.javac.ParticipatesInPreview;
    +
     /**
      * Defines the API of the Java SE Platform.
      *
    @@ -38,7 +40,9 @@
      * @moduleGraph
      * @since 9
      */
    +@ParticipatesInPreview
     module java.se {
    +    requires transitive java.base;
         requires transitive java.compiler;
         requires transitive java.datatransfer;
         requires transitive java.desktop;

The JLS draft is attached as "Module Import Declarations (Second Preview) - JLS.pdf" and is also available for convenience here:
https://cr.openjdk.org/~gbierman/jep494/jep494-20241024/specs/module-import-declarations-jls.html

The JVMS draft is attached as "Module Import Declarations (Second Preview) - JVMS.pdf" and is also available for convenience here:
https://cr.openjdk.org/~gbierman/jep494/jep494-20241024/specs/module-import-declarations-jvms.html

Comments
[~darcy] Here's my take: The preview feature allows any module to declare `requires transitive java.base`. We'd also like `java.se` to have a transitive dependency on java.base. But clearly we can't just change the definition because we'd have to compile java.se as a preview feature. How to break this cycle? It turns out that JEP 12 offers a solution where it is possible to speak of some code as "participating in a preview feature", i.e. it can use a preview feature but not itself be considered a preview feature. So, we are saying that the java.se module declaration is participating in the preview feature, so it is allowed to transitively depend on java.base but it itself is not considered a preview feature, so it can be compiled and loaded with requiring the preview flag. My understanding is this is what has been implemented. There is some discussion of this in the spec change document in ยง1.5. Hope this helps.
30-10-2024

Hmm. I have some questions about the intended semantics here related to the updates to the java.se module. Is that intended effect that without --preview-enable, in JDK 24 java.se act exactly the same way it does today (no "requires transitive java.base"), but when --preview-enable is present, acts as if requires transitive java.base were present? I think those would be reasonable semantics, but it isn't clear to me if the PR implements those semantics. Does src/java.base/share/classes/jdk/internal/module/ModuleInfo.java screen out the require transitive at runtime if --preview-enable is false? How for javadoc generation and other compile-time contexts? Would the javadoc page for teh java.se module, https://download.java.net/java/early_access/jdk24/docs/api/java.se/module-summary.html in JDK 24 after this changes goes in list "requires transitive java.se"?
30-10-2024

To add some technical details: the `module-info` for `java.se` contains `requires transitive java.base;`, regardless of preview status. The `module-info.class` for `java.se` is not marked as preview, as the module is "participating in preview" (which only JDK modules can), and hence its classfiles do not have to be marked when using the preview features. But it is not hiding the fact the directive is there - the javadoc will show it, as will any reflective API, or any client reading the classfile, regardless of the preview status of the VM running the reflective API. In other words, the javadoc for `java.se` will show `java.base` under "Indirect Exports". Overall, the impact of this should be very limited, and the specification tries to be upfront about this. Regarding javac, javadoc and runtime checking that the classfile is marked as preview when seeing `requires transitive java.base;`, yes they all should do that, and should rejects `module-info.class` not marked as preview with `requires transitive java.base;`. Except for modules that "participate in preview" i.e. `java.se`, where the preview flag is ignored. But all custom `module-info`s with `requires transitive java.base;` without the preview flag will be rejected by both javac and the runtime.
30-10-2024

[~darcy] Draft specs attached.
24-10-2024

Moving to Provisional.
20-10-2024