Java 9错误:不在模块源路径上

9

项目结构

我有一个用Java 8编写的项目,想要将其更新为Java 9。因此,我将类分成了两个独立的模块。这两个模块如下:

  • org.ggp.base模块,在目录org.ggp.base/src/main/java中包含module-info.java文件。在我开始更新到Java 9之前,它的构建是使用Gradle自动化的。该模块使用了pl.edu.prz.klopusz模块中包含的抽象类实现。
  • pl.edu.prz.klopusz模块,在目录pl.edu.prz.klopusz/dolar-app/src/main/java中。我希望使用Maven自动化构建该模块。该模块需要org.ggp.base模块。

文件树形结构如下:

.
├── org.ggp.base/
│   ├── build.gradle
│   └── src/
│       └── main/
│           ├── java/
│           │   ├── external/
│           │   │   └── JSON/
│           │   │       ├── JSONArray.java
│           │   │       └── JSONObject.java
│           │   ├── META-INF/
│           │   │   └── MANIFEST.MF
│           │   ├── module-info.java
│           │   └── org/
│           │       └── ggp/
│           │           └── base/
│           │               └── util/
│           │                   ├── statemachine/
│           │                   │   ├── MachineState.java
│           │                   │   └── StateMachine.java
│           │                   └── symbol/
│           └── resources/
│               └── org/
│                   └── ggp/
│                       └── base/
└── pl.edu.prz.klopusz/
    └── dolar-app/
        └── src/
            └── main/
                └── java/
                    ├── module-info.java
                    └── pl/
                        └── edu/
                            └── prz/
                                └── klopusz/
                                    └── utilities/
                                        └── decorators
                                          └──StateMachineDecorator.java

module-info.java文件的内容如下:

org.ggp.base/src/main/java/module-info.java
module org.ggp.base {
    requires guava;
    requires reflections;
    requires jdk.httpserver;

    uses org.ggp.base.util.statemachine.StateMachine;

    exports org.ggp.base;
}
pl.edu.prz.klopusz/dolar-app/src/main/java/module-info.java
module pl.edu.prz.klopusz {
    requires org.ggp.base;

    provides org.ggp.base.util.statemachine.StateMachine
        with pl.edu.prz.klopusz.utilities.decorators.StateMachineDecorator;
}

编译

我尝试使用以下命令编译该项目:

javac -d out \
  --module-source-path org.ggp.base/src/main/java:pl.edu.prz.klopusz/dolar-app/src/main/java \
  $(find org.ggp.base/src/main/java -name *.java) \
  $(find pl.edu.prz.klopusz/dolar-app/src/main/java -name *.java)

错误

我遇到了以下错误:

org.ggp.base/src/main/java/module-info.java:1:

error: module not found on module source path
module org.ggp.base {

还有其他 99 个位于 org.ggp.base 包内的类的错误,每一个错误都是这样的:

org.ggp.base/src/main/java/external/JSON/JSONObject.java:1:

error: not in a module on the module source path
package external.JSON;

或者

org.ggp.base/src/main/java/org/ggp/base/validator/OPNFValidator.java:1:

error: not in a module on the module source path
package org.ggp.base.validator;

我的要求

我想要消除这些错误并编译项目。我不必保留目录结构,但当我将它们全部放在一起时,用了 2 个 module-info.java 文件,编译器抱怨多个模块。我可以通过 IntelliJ IDEA 完成,但我不知道背后发生了什么,也不知道如何处理错误(Package is empty: org.ggp.base)。

Package is empty: org.ggp.base

我已经找到的信息

很难找到关于 javac 命令中 --module-source-path 开关的文档。我找到了这个网站,它说:

如果你将模块的代码放在一个名为模块的封闭目录中,那么模块源路径就更像是一个简单的路径,例如
--module-source-path Users/Me/MyProject/src
或者如果它位于多个项目中,则使用
    --module-source-path 
        /Users/Me/MyProject/src:/Users/Me/MyOtherProject/src

对于 Windows,请使用反斜杠和分号,但无论如何我都在使用 Linux。

还有一个对开放 JDK 缺陷的评论,与我的错误相同,但我想它仍未解决。

更新

-verbose开关

我在命令的末尾添加了-verbose开关。这是编译器显示的部分内容:

[parsing started SimpleFileObject[/home/sensitive/org.ggp.base/src/main/java/module-info.java]]
[parsing started SimpleFileObject[/home/sensitive/org.ggp.base/src/main/java/org/ggp/base/util/statemachine/MachineState.java]]
[parsing started SimpleFileObject[/home/sensitive/pl.edu.prz.klopusz/dolar-app/src/main/java/module-info.java]]
[parsing started SimpleFileObject[/home/sensitive/pl.edu.prz.klopusz/dolar-app/src/main/java/pl/edu/prz/klopusz/utilities/decorators/StateMachineDecorator.java]]
org.ggp.base/src/main/java/org/ggp/base/util/statemachine/MachineState.java:1: error: not in a module on the module source path
package org.ggp.base.util.statemachine;
^
[loading /modules/jdk.httpserver/module-info.class]
[loading /modules/java.base/module-info.class]
[total 263ms]
100 errors

所以,我认为这不是--module-source-path开关中路径的错误(与@StephanHerrmann指出的*src/main/java相同的行为发生)。它读取应该读取的所有Java源代码。在pl.edu.prz.klopusz模块中的源代码没有问题。 这是org.ggp.base.util.statemachine.MachineState的前几行:
package org.ggp.base.util.statemachine;

import org.ggp.base.util.gdl.grammar.GdlSentence;

import java.util.HashSet;
import java.util.Set;

public class MachineState {
    //...
}

@StephanHerrmann,我使用*/src/main/javaorg.ggp.base/src/main/java:pl.edu.prz.klopusz/dolar-app/src/main/java都无所谓。 - banan3'14
您的目录布局不完全符合 */src/main/java 模式,因为存在额外的 dolar-app 中间目录,这妨碍了与模块名的匹配。 - Stephan Herrmann
被接受的答案没有说出确切的javac命令应该是什么样子,你也没有。为了完整起见,它应该是javac -d out --module-source-path "./*/src/main/java/" $(find . -name "*.java"),对吧? - Abhijit Sarkar
@AbhijitSarkar 差不多。由于某种原因,我必须使用 $(find org.ggp.base/src/main/java -name *.java) $(find pl.edu.prz.klopusz/src/main/java -name *.java),因为在当前目录中简单搜索 find . 不起作用。我会把它添加到答案 https://stackoverflow.com/review/suggested-edits/21296807。 - banan3'14
我不明白为什么像我展示的find不起作用;这与javac无关。我认为你在find方面做错了什么。您的编辑因不同原因被拒绝,我会将我的评论发布为答案。 - Abhijit Sarkar
显示剩余2条评论
2个回答

19
根据JEP 261--module-source-path选项(用于在“多模块模式”下编译)必须指向一个目录,其中包含每个包含模块的子目录,其中目录名称必须等于模块名称。

为了适应源不直接包含在模块目录中的布局,该选项支持模式,其中可以使用符号*来表示路径的任何部分中的模块名称,例如"./*/src/main/java/",它将在./my.mod1/src/main/java/module-info.java找到模块my.mod1等。

JEP 261没有提到*可以出现在模式的哪个位置,但显然javac不喜欢以*开头的模式。这可能是有意的,也可能不是。

稍微相关的是,我想补充说,在以前的讨论中,我被告知JEP 261包含过时的信息,但我的问题是,在完成JEP后是否会维护此规范,但没有得到答案。javac手册条目不是提供像--module-source-path这样的选项的足够详细的信息的地方。


7

为了完整起见,完整的javac命令如下:

javac -d out --module-source-path "./*/src/main/java/" $(find . -name "*.java")

根据OpenJDK的官方教程(稍作修改后如下所示的目录结构),结合OpenJDK版本“11.0.1”,上述命令javac对我有效:

.
├── com.greetings
│   └── src
│       └── main
│           └── java
│               ├── com
│               │   └── greetings
│               │       └── Main.java
│               └── module-info.java
├── org.astro
│   └── src
│       └── main
│           └── java
│               ├── module-info.java
│               └── org
│                   └── astro
│                       └── World.java
├── out
│   ├── classes
│   │   ├── com.greetings
│   │   │   ├── com
│   │   │   │   └── greetings
│   │   │   │       └── Main.class
│   │   │   └── module-info.class
│   │   └── org.astro
│   │       ├── module-info.class
│   │       └── org
│   │           └── astro
│   │               └── World.class
│   └── lib
│       ├── com.greetings.jar
│       └── org.astro@1.0.jar

你知道如何在Windows上编写 javac -d out --module-source-path "./*/src/main/java/" $(find . -name "*.java") 而不是Linux/Mac OS吗? - invzbl3
@invzbl3 我认为PowerShell可能提供了一组更有用的命令行实用程序,模仿Unix的find命令。否则,您可以在Windows中安装bash(或其他)shell。我认为Cygwin是通用/GNU实现,尽管我只是使用Git工具提供的工具包和shell。那个bash shell(我怀疑是cygwin)运行得很好,并且有“find”和大多数其他工具。学习bash,您将永远不会回头 :) - Toby Eggitt
2
这是一个老问题,但以防万一有人偶然遇到:你应该能够在Windows命令提示符中执行以下操作: dir /s /b *.java > mySourceFiles.txt & javac -d out --module-source-path ".*\src\main\java" @sourceFiles.txt & del mySourceFiles.txt - markus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接