补丁 Java 9 模块,带有测试代码以处理反射

Patch Java 9 module with test-code to work with reflections

如何在测试运行时将我的测试添加到我的生产代码中,以便两者都在同一个 Java 9 模块中并且可以使用反射相互访问?

到目前为止我已经尝试过:

所以我的完整测试线是:

java \
  --patch-module com.Whosebug.examplemodule=ModuleInfoTest:ModuleInfoExample \
  --module-path ModuleInfoExample \
  --add-opens com.Whosebug.examplemodule/com.Whosebug.examplepackage=com.Whosebug.examplemodule \
  --add-opens com.Whosebug.examplemodule/com.Whosebug.examplepackage=ALL-UNNAMED \
  --module com.Whosebug.examplemodule/com.Whosebug.examplepackage.Main

我在包含以下子目录和文件的目录中:

我正在使用:

openjdk version "13.0.2" 2020-01-14
OpenJDK Runtime Environment (build 13.0.2+8)
OpenJDK 64-Bit Server VM (build 13.0.2+8, mixed mode, sharing)



As I learned from the approved answer, my problem was not really "access other classes", as I phrased it. But more like find them (by scanning classpath/modulepath). However this part is already .

来自 Oracle's Java 13 java command 这些是您尝试使用的两个选项:

--add-opens module/package=target-module(,target-module)*
--patch-module module=file(;file)*

但是:

  • --add-opens 对您没有帮助,因为它向其他模块打开了一个模块。您只有一个模块。
  • --patch-module 必须指定要修补到模块中的目录(或 jarfile)。我注意到这里有一个 ; 而不是您使用的 :。在我看来,您一直在告诉 java 从您的模块所在的目录中使用 :ModuleInfoExample.
  • 修补文件

您只需将 ModuleInfoTest/ 中的文件添加到您的模块中。 我根据您的问题创建了结构,运行 它:

正在编译:

javac -d target/ModuleInfoExample src/ModuleInfoExample/*.java src/ModuleInfoExample/com/Whosebug/examplepackage/*.java
javac -cp target/ModuleInfoExample -d target/ModuleInfoTest src/ModuleInfoTest/com/Whosebug/examplepackage/*.java

运行 来自模块的主要内容 - 未添加 类:

java --module-path target/ModuleInfoExample --module com.Whosebug.examplemodule/com.Whosebug.examplepackage.Main

prints:
Hello world - I'm private

运行 来自模块的 AnyClass - 未添加 类 - 预期异常

java --module-path target/ModuleInfoExample --module com.Whosebug.examplemodule/com.Whosebug.examplepackage.AnyClass

Error: Could not find or load main class com.Whosebug.examplepackage.AnyClass in module com.Whosebug.examplemodule

运行 来自模块的 AnyClass - 将 AnyClass 添加到包中:

java --module-path target/ModuleInfoExample --patch-module com.Whosebug.examplemodule=target/ModuleInfoTest --module com.Whosebug.examplemodule/com.Whosebug.examplepackage.AnyClass

prints:
Inside AnyClass - calling Main: Hello world - I'm private

  field.get() = I'm private
  field.get() = I'm not private anymore

总结构:

>tree /f
..snip..
C:.
+---src
¦   +---ModuleInfoExample
¦   ¦   ¦   module-info.java
¦   ¦   ¦
¦   ¦   +---com
¦   ¦       +---Whosebug
¦   ¦           +---examplepackage
¦   ¦                   Main.java
¦   ¦
¦   +---ModuleInfoTest
¦       +---com
¦           +---Whosebug
¦               +---examplepackage
¦                       AnyClass.java
¦
+---target
    +---ModuleInfoExample
    ¦   ¦   module-info.class
    ¦   ¦
    ¦   +---com
    ¦       +---Whosebug
    ¦           +---examplepackage
    ¦                   Main.class
    ¦
    +---ModuleInfoTest
        +---com
            +---Whosebug
                +---examplepackage
                        AnyClass.class

src\ModuleInfoExample\module-info.java:

module com.Whosebug.examplemodule {
//  exports com.Whosebug.examplepackage; // no need to export. Nothing is using this
}

src\ModuleInfoExample\com\Whosebug\examplepackage\Main.java:

package com.Whosebug.examplepackage;

public class Main {
  private String privateString = "I'm private";

  public static void main(String[] args) {
    new Main().hello();
  }
  public void hello(){
    System.out.println("Hello world - " + privateString);
  }
}

src\ModuleInfoTest\com\Whosebug\examplepackage\AnyClass.java:

package com.Whosebug.examplepackage;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class AnyClass {
  public static void main(String[] args) {
    testhello();
    System.out.println();
    breakhello();
  }

  public static void testhello(){
    System.out.print("Inside AnyClass - calling Main: ");
    Main test = new Main();
    test.hello();
  }

  public static void breakhello(){
    try {
      // Not necessary - same package, but..
      Class<?> mainClass = Class.forName("com.Whosebug.examplepackage.Main");
      Constructor<?> constructor = mainClass.getConstructor();
      Object main = constructor.newInstance();

      // Getting, printing and changing the field..
      Field field = mainClass.getDeclaredField("privateString");
      field.setAccessible(true);
      System.out.println("  field.get() = " + field.get(main));
      field.set(main,"I'm not private anymore");
      System.out.println("  field.get() = " + field.get(main));

    } catch (Exception e) {  // Sorry, all in one big bucket
       System.out.println("Error: " + e);
    }
  }
}