【问题标题】:How to make Java class invisible outside its module for other non-modular projects?对于其他非模块化项目,如何使 Java 类在其模块之外不可见?
【发布时间】:2020-09-05 08:11:49
【问题描述】:

最近我发现,如果模块内的包包含公共接口或类,它们会自动导出,因此在接收者代码未模块化时无意中在模块外部可见。

项目结构如下

parent

   sub-donor                      (java-module)
       my/project/first
           Cowboy.java
       module-info.java

   sub-recipient                  (has no module-info)
       my/project/somewhere
           Main.java 

模块信息.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 包中的类应该只在my.donor 模块中使用,并且在模块外是不可见的。

没想到在模块外可见,好像有exports my.project.first;行,所以类Main可以编译。

限制可见性的方法是使sub-recipient成为一个java模块,添加module-info.java,然后sub-donor内部的所有内容都按预期隐藏。当然,对于任何其他非模块化项目,my.donor 模块中的每个公共类仍然可见。

请在 GitHub 上查看最小的working example

我很好奇这是一个错误还是有意识的设计。 这种方法的目的是什么?

【问题讨论】:

  • “出乎意料地它们是可见的” 你是如何确定这一点的?好奇你的module.info 中是否有opens 指令,并在运行时得出这个结论。
  • @Michael, @Naman 我已经更新了这个问题。当接收模块没有module-info.java 文件时,可以重现该问题。附上github上的一个例子。
  • 请您编辑您的问题以包含您运行的产生您报告的行为的 full 命令吗? TIA。
  • @deduper 完整命令只是父项目上的mvn compile。问题是编译时sub-recipientsub-donor 模块的内部包的可见性。

标签: java interface visibility java-module module-info


【解决方案1】:

TL;DR — Maven 的问题。使用 javac 直接编译按预期工作。


冗长的版本

...完整的命令只是在父项目上 mvn 编译...

这就是你的问题。 Maven 有一个令人惊讶的特性,它只会将子项目视为 JPMS 模块IFF 所有子项目都有模块描述符。

所以因为只有你的 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多