Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8190341

When "--patch-module" is used to patch code into a JDK9 platform module, any dependent classes on the classpath CANNOT be located

    Details

      Description

      FULL PRODUCT VERSION :
      java version "9.0.1"
      Java(TM) SE Runtime Environment (build 9.0.1+11)
      Java HotSpot(TM) 64-Bit Server VM (build 9.0.1+11, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [Version 6.1.7601]

      Windows 7
      Windows 10
      Windows Server 2012
      Windows Server 2016


      A DESCRIPTION OF THE PROBLEM :
      Essentially, the problem is that when “--patch-module” is used to patch code into a JDK9 platform module (e.g. java.base, java.corba etc.), any dependent classes made available on the classpath CANNOT be located. However, if the same code is patched into a user-defined module, the dependent classes on the classpath CAN be located.

      My sample program that illustrates this consists of the following components:
      (NOTE: I would have uploaded the .zip file containing all sources and build files, but alas you don't provide an upload-file facility ...)

      1) User-defined module “mymod”, consisting of one simple Java class “Main.java”. This module is really just used for patching code into, in order to show the difference between patching code into a user-defined module and patching code into a JDK9 platform module (e.g. java.base, java.corba etc.).

      package com.mymod;

      public class Main {
          public static void main(String[] args) {
              System.out.println("In mymod's main()!");
          }
      }


      The module-info.java is:
      module mymod { }


      2) MyClassA, in its own package “com.A”, in jar file “A.jar”. MyClassA creates an instance of MyClassB (see below).

      package com.A;

      import com.B.MyClassB;

      public class MyClassA {

              public static void main(String args[]) {
                      System.out.println("In MyClassA's main()!");
                      MyClassB b = new MyClassB();
                      System.out.println("Successfully created instance of MyClassB!");
              }
      }

      3) MyClassB, in its own package “com.B”, in jar file “B.jar”.

      package com.B;

      public class MyClassB {
              public MyClassB() {
              }
      }



      When MyClassA is patched into user-defined module “mymod”, with MyClassB on the classpath, the main() method of MyClassA runs without error (and creates an instance of MyClassB).

      >java --module-path mods --patch-module mymod=A.jar -cp B.jar --add-reads mymod=ALL-UNNAMED -m mymod/com.A.MyClassA

      In MyClassA's main()!
      Successfully created instance of MyClassB!



      When MyClassA is patched into JDK9 platform module “java.base”, with MyClassB on the classpath, the main() method of MyClassA runs but results in the following error trying to load MyClassB:

      >java --patch-module java.base=A.jar -cp B.jar --add-reads java.base=ALL-UNNAMED -m java.base/com.A.MyClassA

      In MyClassA's main()!
      Exception in thread "main" java.lang.NoClassDefFoundError: com/B/MyClassB
             at java.base/com.A.MyClassA.main(MyClassA.java:9)



      When MyClassA is patched into JDK9 platform module “java.corba”, with MyClassB on the classpath, the main() method of MyClassA runs but results in the following error trying to load MyClassB:

      >java --add-modules java.corba --patch-module java.corba=A.jar -cp B.jar --add-reads java.corba=ALL-UNNAMED -m java.corba/com.A.MyClassA

      In MyClassA's main()!
      Exception in thread "main" java.lang.NoClassDefFoundError: com/B/MyClassB
              at java.corba@9.0.1/com.A.MyClassA.main(MyClassA.java:9)
      Caused by: java.lang.ClassNotFoundException: com.B.MyClassB
              at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
              at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
              ... 1 more


      According to the JDK9 documentation we’ve read, the rules for locating classes on the classpath should be the same for code patched into JDK9 platform modules as it is for user-defined modules, but this doesn’t seem to be the case.


      Another thing I noticed is that if you omit the “—add-reads <module-name>=ALL-UNNAMED” from the command-line, then in the case of patching a user-defined module, you get a useful error message alerting you to the fact that the module doesn’t read the unnamed module:

      >java --module-path mods --patch-module mymod=A.jar -cp B.jar -m mymod/com.A.MyClassA

      In MyClassA's main()!
      Exception in thread "main" java.lang.IllegalAccessError: class com.A.MyClassA (in module mymod) cannot access class com.B.MyClassB (in unnamed module @0x9f70c54) because module mymod does not read unnamed module @0x9f70c54
              at mymod/com.A.MyClassA.main(MyClassA.java:9)

      However, if you omit the “—add-reads <module-name>=ALL-UNNAMED” from the command-line in the case of patching a JDK9 platform module, you don’t get this type of useful message:

      >java --patch-module java.base=A.jar -cp B.jar -m java.base/com.A.MyClassA

      In MyClassA's main()!
      Exception in thread "main" java.lang.NoClassDefFoundError: com/B/MyClassB
              at java.base/com.A.MyClassA.main(MyClassA.java:9)



      The source code is organised as follows:

      └───com
          ├───A
          │ MyClassA.java
          │
          ├───B
          │ MyClassB.java
          │
          └───mymod
                  Main.java
                  module-info.java

      build.bat:
      @echo off

      @echo Build started.

      @call clean.bat

      javac -d classesB src\com\B\MyClassB.java
      javac -d classesA -cp classesB src\com\A\MyClassA.java

      jar cvf B.jar -C classesB/ com
      jar cvf A.jar -C classesA/ com

      javac -d mods\mymod src\com\mymod\module-info.java src\com\mymod\Main.java

      @echo Build finished.


      clean.bat:
      @echo off
      rmdir/s/q classesA >nul 2>&1
      rmdir/s/q classesB >nul 2>&1
      del A.jar >nul 2>&1
      del B.jar >nul 2>&1
      rmdir/s/q mods >nul 2>&1


      run.bat:
      @echo off

      @echo (1) Invoke my module's main() method:
      java --module-path mods -m mymod/com.mymod.Main

      @echo.

      @echo (2) Patch MyClassA into my module and invoke MyClassA's main() method:
      java --module-path mods --patch-module mymod=A.jar -cp B.jar --add-reads mymod=ALL-UNNAMED -m mymod/com.A.MyClassA

      @echo.

      @echo (3) Patch MyClassA into java.base module and invoke MyClassA's main() method:
      java --patch-module java.base=A.jar -cp B.jar --add-reads java.base=ALL-UNNAMED -m java.base/com.A.MyClassA

      @echo.

      @echo (4) Patch MyClassA into java.corba module and invoke MyClassA's main() method:
      java --add-modules java.corba --patch-module java.corba=A.jar -cp B.jar --add-reads java.corba=ALL-UNNAMED -m java.corba/com.A.MyClassA
      @echo.



      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Please see supplied description.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      I would expect --patch-module used on JDK9 platform modules to have the same behavior as that on user-defined modules, w.r.t. locating classes on the classpath. As far as I can see, using --patch-module on JDK9 modules is BROKEN.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Please see supplied description.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      Please see supplied description.

      ---------- END SOURCE ----------

        Attachments

          Activity

            People

            • Assignee:
              alanb Alan Bateman
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: