除非使用相同的命令编译包类,否则不会编译模块信息



我有一个名为myModule的文件夹。在里面,还有另一个名为myPackage的文件夹,其中存在我的Main.class

myPackage旁边,我有我想要编译的module-info.java。首先看一下文件夹层次结构:

--  myModule
--  myPackage
--  Main.class
--  module-info.java

问题是当我想用以下命令编译module-info.java时:

javac module-info.java

我得到以下错误:

package is empty or does not exist: myPackage

但是,当我把Main.java放在myPackage中,然后用相同的命令编译这两个文件时:

javac module-info.java myPackage/Main.java

错误消失。我不明白为什么会发生这种事?

TL;DR --模块信息.java文件并非设计为独立的文件。它被设计为多源文件编译单元的一部分。包含模块描述符的单元,加上至少一个其他文件。


冗长版本

">…还有另一个名为myPackage的文件夹,其中存在我的Main.class">

我想你是想键入Main.java,而Main.class是一个疏忽,因为…

  1. 您没有提到它是一个已经编译的字节码文件
  2. 我想不出为什么有人会故意将.class文件放在源目录中

我也会假设——尽管你在问题中根本没有提到它——你有意遵循项目Jigsaw中推荐的惯例:模块系统快速入门指南

">…按照惯例,模块的源代码位于模块名称目录中…">

我已经确定,如果您的myModule模块只是一个空的module{}块,编译就会成功。也就是说,如果它没有声明它exports myPackage。所以我还假设你的模块信息.java,就像我的实验模块一样,包含…

module myModule { 
exports myPackage;
}

请记住javac工具的设计用途

描述

javac命令读取源文件,这些文件包含用Java编程语言编写的模块、包和类型声明…

还要考虑JPMS的可靠配置目标

可靠的配置,用程序组件声明显式相互依赖的方式来取代脆弱、易出错的类路径机制

如果我签了一份每周六给你修剪草坪的合同,但却从来没有来过,我有多可靠?想象一下,如果javac声称导出包的模块编译module-info.java文件是合法的,但该包中没有类。这样的模块有多可靠?

如果我的构建从Maven Central下载了你假设的myModule工件,我的类中可能会有一个import myPackage.*,但却发现里面什么都没有。一个什么都没有的包有什么用?

">问题是当我想用以下命令编译模块-info.java时:">

javac module-info.java

myPackage目录包含合法源代码时,上述命令会导致相同的错误,这是神秘之处的线索。

错误消息不会告诉您文件系统目录为空。它告诉您,您声称模块导出的是空的。空,如:编译器对源代码一无所知,您永远不会将其作为编译单元的一部分传递给它

">……错误消失。我不明白为什么会发生这种事">

通过执行:javac module-info.java myPackage/Main.java,您正在组成一个编译单元,该单元由模块声明其导出的内容组成。JPMS文档指定系统预期使用的方式是

$ javac -d mods/com.greetings 
src/com.greetings/module-info.java 
src/com.greetings/com/greetings/Main.java

因此,尽管存在拼写错误,但您报告的错误原因非常简单:编译一个不包含任何源文件的模块不仅毫无意义,而且就编译器而言,这是一个格式错误的模块。因此,这是违法的

好吧,今天我遇到了这个问题,我遇到了和你一样的问题:我没有源代码。然而,我发现javac不需要您有实际的源代码,只需要在每个导出的包中一个java源文件。

我的解决方案是创建一个powershell脚本,该脚本复制文件层次结构,向每个名称为有效java包名称的目录添加伪java文件,并编译

# Initial folder heirarchy:
# 
# --  staging
# --  myModule
#     --  myPackage
#         --  Main.class
#     --  module-info.java
# copy folder hierarchy (without files) from myModule to staging
xcopy myModule* staging /t /e
# don't forget to copy the module-info.java file
Copy-Item myModule/module-info.java staging
# Get an array of all directories in staging
$Packages = Get-ChildItem staging -Directory -Recurse
# Iterate over those directories
:packageLoop foreach ($Package in $Packages) {
# Each dummy file needs a package declaration at the top, so this generates the package name
$PackageName = ''
$PackageDir = $Package
while ($PackageDir.FullName -ne (Get-Item staging).FullName) {
if (-Not ($PackageDir.Name | Select-String -Pattern '^[a-z$_][a-z$_0-9]*$' -Quiet)) {
# skips over this directory if package name is invalid
continue packageLoop
}
$PackageName = "$($PackageDir.Name).$PackageName"
$PackageDir = $PackageDir.Parent
}
$PackageName = $PackageName.Substring(0, $PackageName.Length - 1)
# Creates the dummy file Foo.java
New-Item "$($Package.FullName)/Foo.java" -ItemType File -Value "package $PackageName ; public class Foo { }" | Out-Null
}
# Compiles entire staging directory, including module-info.java
javac -d staging (Get-ChildItem staging* -Recurse -File | Select-Object -ExpandProperty FullName)
# module-info.class can now be found at staging/module-info.class

相关内容

  • 没有找到相关文章

最新更新