我有一个名为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
是一个疏忽,因为…
- 您没有提到它是一个已经编译的字节码文件
- 我想不出为什么有人会故意将.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