Patched Java 9 Module Test Code Working and Thinking
itching:
How can I add my tests to my production code during a pilot run so that both are the same Java 9 module and can access each other using reflection?
So far I have tried:
- Removed Java Modularity 9 (actually
module-info.java
) → it worked perfectly, but not what I was looking for. - Moved the dedicated module I tested (and therefore also the package) → it worked perfectly, but not what I was looking for. (I guess my unit tests are close to my code.)
- Using
--patch-module
to other folders is almost added (to a specified use--module-path
) → it works with "normal" code, but not with reflection, it doesn't find the specified class--module-path
.- Use Specify both my test and production code
--patch-module
→ find only classes in the folder I specified first. - Adding it explicitly
--add-opens mymodule/mypackge=mymodule
or...=ALL-UNNAMED
turning it on for reflection → doesn't seem to make any difference.
- Use Specify both my test and production code
So my full test route is:
java \
--patch-module com.stackoverflow.examplemodule=ModuleInfoTest:ModuleInfoExample \
--module-path ModuleInfoExample \
--add-opens com.stackoverflow.examplemodule/com.stackoverflow.examplepackage=com.stackoverflow.examplemodule \
--add-opens com.stackoverflow.examplemodule/com.stackoverflow.examplepackage=ALL-UNNAMED \
--module com.stackoverflow.examplemodule/com.stackoverflow.examplepackage.Main
I am in a directory containing the following subdirectories and files:
- ModuleInfoExample /模块info.class
- ModuleInfoExample/com/calculator/examplepackage/Main.class
- ModuleInfoTest/com/calculator/examplepackage/AnyClass.class
I am using:
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 wasn't really " accessing other classes", as I put it. But prefer to find them (by scanning classpath/ModulePath). However, this other StackOverflow question has been answered in part .
Scratte:
From Java 13 java commands these are the two options you are trying to use:
--add-opens module/package=target-module(,target-module)*
--patch-module module=file(;file)*
but:
--add-opens
Because it opens up a module, other modules don't help you. You only have one module.--patch-module
The directory (or in jarfiles) to patch into the module must be specified. I noticed that there is one you;
don't:
like to use. It seems to me that you have told java to patch files from the same directory where your module is there:ModuleInfoExample
.
You just need to add the file from ModuleInfoTest/
to your module. I generated the structure from your question and ran it:
Compile:
javac -d target/ModuleInfoExample src/ModuleInfoExample/*.java src/ModuleInfoExample/com/stackoverflow/examplepackage/*.java
javac -cp target/ModuleInfoExample -d target/ModuleInfoTest src/ModuleInfoTest/com/stackoverflow/examplepackage/*.java
Run main from module - no added class:
java --module-path target/ModuleInfoExample --module com.stackoverflow.examplemodule/com.stackoverflow.examplepackage.Main
prints:
Hello world - I'm private
Running AnyClass from module - no class added - exception expected
java --module-path target/ModuleInfoExample --module com.stackoverflow.examplemodule/com.stackoverflow.examplepackage.AnyClass
Error: Could not find or load main class com.stackoverflow.examplepackage.AnyClass in module com.stackoverflow.examplemodule
Run AnyClass from a module - add AnyClass to the package:
java --module-path target/ModuleInfoExample --patch-module com.stackoverflow.examplemodule=target/ModuleInfoTest --module com.stackoverflow.examplemodule/com.stackoverflow.examplepackage.AnyClass
prints:
Inside AnyClass - calling Main: Hello world - I'm private
field.get() = I'm private
field.get() = I'm not private anymore
General structure:
>tree /f
..snip..
C:.
+---src
¦ +---ModuleInfoExample
¦ ¦ ¦ module-info.java
¦ ¦ ¦
¦ ¦ +---com
¦ ¦ +---stackoverflow
¦ ¦ +---examplepackage
¦ ¦ Main.java
¦ ¦
¦ +---ModuleInfoTest
¦ +---com
¦ +---stackoverflow
¦ +---examplepackage
¦ AnyClass.java
¦
+---target
+---ModuleInfoExample
¦ ¦ module-info.class
¦ ¦
¦ +---com
¦ +---stackoverflow
¦ +---examplepackage
¦ Main.class
¦
+---ModuleInfoTest
+---com
+---stackoverflow
+---examplepackage
AnyClass.class
SRC \ ModuleInfoExample \ module-info.java:
module com.stackoverflow.examplemodule {
// exports com.stackoverflow.examplepackage; // no need to export. Nothing is using this
}
SRC\ModuleInfoExample\COM\Calculator\examplepackage\Main.java:
package com.stackoverflow.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\Calculator\examplepackage\AnyClass.java:
package com.stackoverflow.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.stackoverflow.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);
}
}
}