I've been pondering the Java module system and had a question I didn't find addressed here. I poked around a bit more and worked out an answer, so I guess I'll post the info, in case it shortens anyone else's search.
Traditionally, tests are kept in a separate source tree from the main body of a project's code, so the test binaries are easy to separate out of the resulting project's final deliverable. I was unsure how to achieve this with the module system, but it turns out it's still easy.
Our sources for (potentially multi-module) module projects are generally laid out something like "sources/MyModule/src/main/java"
. We would then specify compilation using --module-source-path
set to "source/*/src/main/java"
(Note that the quotes are important or your OS will try to expand the asterisk. You don't want that, you want to hand it to javac
). And if there are other modules under source, provided they also have the same overall structure, just differing by their names, they will be found and compiled. But, it turns out we seem to be able to split a module across two trees. So, this source layout:
.
└── sources
├── ModOne
│ ├── java
│ │ ├── module-info.java
│ │ └── pkg
│ │ └── Prod.java
│ └── test
│ └── pkg
│ └── Test.java
└── ModTwo
└── java
├── module-info.java
└── p2
└── RunMe.java
Compiles correctly in one go with this command:
javac -d out --module-source-path "./sources/*/java:./sources/*/test" --module ModTwo,ModOne
Notice I don't specify ModOne the test part doesn't get compiled, but so long as I do so explicitly, it is found, and the output created this directory tree:
.
├── out
│ ├── ModOne
│ │ ├── module-info.class
│ │ └── pkg
│ │ ├── Prod.class
│ │ └── Test.class
│ └── ModTwo
│ ├── module-info.class
│ └── p2
│ └── RunMe.class
The main method in RunMe executes like this:
java --module-path out --module ModTwo/p2.RunMe
and there's actually a main in my Test class, which runs and successfully has package level access to the rest of ModOne's code.
Contents of the source files in the trees:
sources/ModOne/java/module-info.java:
module ModOne {
exports pkg;
}
sources/ModOne/java/pkg/Prod.java:
package pkg;
public class Prod {
public static String name = "Fred";
}
sources/ModOne/test/pkg/Test.java:
package pkg;
public class Test {
public static void main(String [] args) {
System.out.println("Value is " + Prod.name);
}
}
sources/ModTwo/java/module-info.java:
module ModTwo {
requires ModOne;
}
sources/ModTwo/java/p2/RunMe.java:
package p2;
public class RunMe {
public static void main(String [] args) {
System.out.println("Pulling from ModOne I get name is " + pkg.Prod.name);
}
}