如何使 Java class 在其他非模块化项目的模块外不可见?
How to make Java class invisible outside its module for other non-modular projects?
最近我发现,如果模块内的包包含 public 接口或 classes,它们将被自动导出,因此在收件人代码为未模块化。
项目结构如下
parent
sub-donor (java-module)
my/project/first
Cowboy.java
module-info.java
sub-recipient (has no module-info)
my/project/somewhere
Main.java
模块-info.java
module my.donor {
// nothing is exported here
}
Cowboy.java
public class Cowboy {
public String say() { return "eee-ha"; }
}
Main.java
import my.project.first.Cowboy;
public class Main {
public static void main(String[] args) {
Cowboy g = new Cowboy();
System.out.println(g.say());
}
}
my.project.first
包中的 class 应该只在 my.donor
模块中使用,并且在模块外是不可见的。
没想到在模块外可见,好像有exports my.project.first;
行,所以classMain
可以编译
限制可见性的方法是使sub-recipient
成为java模块,添加module-info.java
,然后sub-donor
内的所有内容都会按预期隐藏。当然,对于任何其他非模块化项目,my.donor
模块中的每个 public class 仍然可见。
请在 GitHub 上查看最小 working example。
很好奇到底是bug还是有意识的设计。
这种方法的目的是什么?
TL;DR — Maven 的问题。使用 javac
编译直接按预期工作。
long-winded版本
„…Full command is just mvn compile on the parent project…“
这就是你的问题。 Maven 有一个令人惊讶的 特性,它只会将子项目视为 JPMS 模块 IFF all子项目有模块描述符。
所以因为只有你的 sub-donor
Maven 模块有 JPMS 模块描述符,你的两个子项目都在类路径上编译......
$ mvn -e -X compile
…
[INFO] Changes detected - recompiling the module!
[DEBUG] Classpath:
[DEBUG] sample-so-question-61888059-dev/sub-recipient/target/classes
[DEBUG] sample-so-question-61888059-dev/sub-donor/target/classes
…
[DEBUG] Command line options:
[DEBUG] -d sample-so-question-61888059-dev/sub-recipient/target/classes -classpath sample-so-question-61888059-dev/sub-recipient/target/classes;sample-so-question-61888059-dev/sub-donor/target/classes;…
…
并且因为两者都在类路径上,sub-donor
子项目的模块描述符被渲染为无效。
如果你自己动手 运行 javac
(假设你已经编译了 sub-donor
预先项目)…
javac --add-modules my.donor --module-path sample-so-question-61888059-dev/sub-donor/target/classes --class-path sample-so-question-61888059-dev/sub-recipient/target/classes -d sample-so-question-61888059-dev/sub-recipient/target/classes sample-so-question-61888059-dev/sub-recipient/src/main/java/my/somewhere/*.java
那么javac
确实是有意设计的退缩了……
sample-so-question-61888059-dev/sub-recipient/src/main/java/my/somewhere/Main.java:3: error: package my.project.first is not visible
import my.project.first.Cowboy;
^
(package my.project.first is declared in module my.donor, which does not export it)
1 error
最近我发现,如果模块内的包包含 public 接口或 classes,它们将被自动导出,因此在收件人代码为未模块化。
项目结构如下
parent
sub-donor (java-module)
my/project/first
Cowboy.java
module-info.java
sub-recipient (has no module-info)
my/project/somewhere
Main.java
模块-info.java
module my.donor {
// nothing is exported here
}
Cowboy.java
public class Cowboy {
public String say() { return "eee-ha"; }
}
Main.java
import my.project.first.Cowboy;
public class Main {
public static void main(String[] args) {
Cowboy g = new Cowboy();
System.out.println(g.say());
}
}
my.project.first
包中的 class 应该只在 my.donor
模块中使用,并且在模块外是不可见的。
没想到在模块外可见,好像有exports my.project.first;
行,所以classMain
可以编译
限制可见性的方法是使sub-recipient
成为java模块,添加module-info.java
,然后sub-donor
内的所有内容都会按预期隐藏。当然,对于任何其他非模块化项目,my.donor
模块中的每个 public class 仍然可见。
请在 GitHub 上查看最小 working example。
很好奇到底是bug还是有意识的设计。 这种方法的目的是什么?
TL;DR — Maven 的问题。使用 javac
编译直接按预期工作。
long-winded版本
„…Full command is just mvn compile on the parent project…“
这就是你的问题。 Maven 有一个令人惊讶的 特性,它只会将子项目视为 JPMS 模块 IFF all子项目有模块描述符。
所以因为只有你的 sub-donor
Maven 模块有 JPMS 模块描述符,你的两个子项目都在类路径上编译......
$ mvn -e -X compile
…
[INFO] Changes detected - recompiling the module!
[DEBUG] Classpath:
[DEBUG] sample-so-question-61888059-dev/sub-recipient/target/classes
[DEBUG] sample-so-question-61888059-dev/sub-donor/target/classes
…
[DEBUG] Command line options:
[DEBUG] -d sample-so-question-61888059-dev/sub-recipient/target/classes -classpath sample-so-question-61888059-dev/sub-recipient/target/classes;sample-so-question-61888059-dev/sub-donor/target/classes;…
…
并且因为两者都在类路径上,sub-donor
子项目的模块描述符被渲染为无效。
如果你自己动手 运行 javac
(假设你已经编译了 sub-donor
预先项目)…
javac --add-modules my.donor --module-path sample-so-question-61888059-dev/sub-donor/target/classes --class-path sample-so-question-61888059-dev/sub-recipient/target/classes -d sample-so-question-61888059-dev/sub-recipient/target/classes sample-so-question-61888059-dev/sub-recipient/src/main/java/my/somewhere/*.java
那么javac
确实是有意设计的退缩了……
sample-so-question-61888059-dev/sub-recipient/src/main/java/my/somewhere/Main.java:3: error: package my.project.first is not visible
import my.project.first.Cowboy;
^
(package my.project.first is declared in module my.donor, which does not export it)
1 error