第 11 章 构建工具和 IDE

Chapter 11. Build Tools and IDEs

In this book, we have been working with java and javac directly on a command line. This is not how most applications are built today. Most projects are built using tools such as Maven or Gradle. These build tools can take care of concerns such as managing the classpath during compilation, dependency management, and building artifacts such as JAR files. On top of that, most developers use an IDE such as Eclipse, IntelliJ IDEA, or NetBeans. IDEs make development easier by providing features such as code completion, error highlighting, refactoring, and code navigation.

本书主要是直接在命令行上使用 java 和 javac,这并不是如今大多数应用程序的构建方式。目前多数项目都是使用 Maven 或 Gradle 等工具构建的。这些构建工具可以处理各种问题,比如在编译期间管理类路径、依赖关系管理以及构建工件(如 JAR 文件)等。最重要的是,大多数开发人员都使用 IDE,比如 Eclipse、IntelliJ IDEA 或 NetBeans。IDE 提供了诸如代码完成、错误突出显示、重构和代码导航等功能,从而使开发更容易。

Both build tools and IDEs need to know what types are available in a given context. Tools typically interact with the classpath to accomplish this. This significantly changes with the introduction of the Java module system. The classpath is no longer the (only) mechanism that controls which types are available. Tools now have to consider the module path as well. Moreover, there might be a mix of explicit modules, the classpath, and automatic modules. At the time of writing, the tool ecosystem is still working hard on Java 9 support. This chapter introduces some of the available tools, and discusses how they support the Java module system or likely will in the near future.

构建工具和 IDE 都需要知道在给定上下文中哪些类型可用。工具通常与类路径进行交互以完成此操作。随着 Java 模块系统的引入,该过程发生了很大的变化。类路径不再是控制哪些类型可用的(唯一)机制,工具现在也必须考虑使用模块路径。而且,还可以混合使用显式模块、类路径和自动模块。在编写本书的时候,工具生态系统仍在努力支持 Java 9。本章介绍了一些可用的工具,并讨论了它们如何支持(或可能在不久的将来支持)Java 模块系统。

11.1 Apache Maven

Building a single module project with Maven is trivial. We will go over the steps to do this now, but we will not present the code or configuration. An example is included in the GitHub repository if you want to try it out: ➥ chapter11/single-module.

使用 Maven 构建单个模块项目是非常容易的一件事情。接下来将完成构建的相关步骤,但是不会介绍代码或配置。GitHub 存储库中包含一个示例,如果愿意可以尝试一下:chapter11/single-module。

Place module-info.java in the project’s src/main/java directory, and Maven will set up the compiler correctly to use the module source path. Dependencies are always put on the module path, even when the dependency isn’t modularized yet. This means dependencies that are not modules yet are always handled as automatic modules. This is different from what we did in Chapter 8 and Chapter 9, where we used a mix of classpath and module path. Both approaches are fine, although putting everything on the module path might hide some future problems. Besides the fact that the output of the project is now a modular JAR, there’s really not much else to see. Maven takes care of this nicely.

将 module-info.java 放在项目的 src/main/java 目录中,那么 Maven 将正确设置编译器以使用模块源路径。即使依赖项还没有模块化,它们通常也是放在模块路径上,这意味着还没有模块化的依赖项总是作为自动模块来处理的。这与第 8 章和第 9 章中所做的不同,这两章混合使用了类路径和模块路径。两种方法都很好,尽管将所有内容放在模块路径上在未来可能会带来一些隐藏的问题。现在,除了项目的输出是一个模块化的 JAR 之外,实际上看不到其他内容。Maven 很好地处理了这个问题。

Although there’s not a lot to see on the surface, a lot is happening internally. Apache Maven now has to take the rules of the Java module system into account. The most important changes made to Apache Maven for support of the Java module system are as follows:

虽然表面上看不到太多东西,但内部却发生了很多事情。Apache Maven 现在必须考虑 Java 模块系统的规则。为了支持 Java 模块系统,Apache Maven 完成了如下重要的更改:

  • Uses the module path during compilation
  • Supports a mix of explicit modules and automatic modules as dependencies

  • 在编译期间使用模块路径。
  • 支持将显式模块和自动模块的混合体作为依赖项。

Interestingly enough, the list doesn’t include anything about integrating the POM with module-info.java, although there is clearly a relationship between dependencies in a POM and requires in module-info.java. It’s not as strange as it might first look. Think about it this way: Apache Maven configures only the module path and classpath. The Java compiler takes this input and uses it to compile sources (including module-info.java). Apache Maven replaces the shell scripts we have been using in this book; it doesn’t replace the Java compiler. Clearly, we need both, but why doesn’t Maven generate a module-info.java for us? This has a lot to do with naming of modules.

有趣的是,上面所做的更改并没有包含任何有关将 POM 与 module-info.java 集成的内容,虽然 POM 中的依赖项和 module-info.java 中的 requires 之间存在明确的关系。这其实并不奇怪。不妨这样来想:Apache Maven 仅配置了模块路径和类路径。Java 编译器接受该配置并使用它来编译源代码(包括 module-info.java)。Apache Maven 取代了本书中所使用的 shell 脚本,但不会取代 Java 编译器。显然,两者都是需要的,但为什么 Maven 不为我们生成一个 module-info.java 呢?这与模块的命名有很大关系。

There are three names in play:

此时共有三个名称:

  • The module’s name defined in module-info.java
  • The Maven project name defined in pom.xml
  • The name of the JAR file generated by Maven

  • 在 module-info.java 中定义的模块名称。
  • pom.xml 中定义的 Maven 项目名称。
  • 由 Maven 生成的 JAR 文件名称。

We will use the module name when we reference to the module from other module-info.java files—for example, to require the module. The Maven name is used when adding a dependency to the module on the Maven level, in pom.xml. Finally, the JAR file generated by the Maven build is what will be shipped for deployment.

当从其他 module-info.java 文件中引用模块(例如,请求模块)时,将会使用模块名称。而在 Maven 级别上,向 pom.xml 中添加依赖项时使用 Maven 名称。最后,由 Maven 构建生成的 JAR 文件将用于部署。

In Maven, a module name, also known as the Maven coordinate, has three parts: groupId : artifactId : version. The groupId is used for namespacing. Many projects of multiple modules exist, and the groupId logically brings them together. Usually the groupId is the reverse domain name of the project. The artifactId is the name of the module. Unfortunately, different projects use different naming strategies. Sometimes the project name is included in the artifactId, sometimes not. Finally, a Maven module is versioned.

在 Maven 中,模块名称(也称为 Maven 坐标)包含三个部分:groupId:-artifactId:version。groupId 用于命名空间。在包含许多模块的项目中,groupId 在逻辑上将这些模块组合在一起。通常,groupId 是项目的反向域名。artifactId 是模块的名称。不幸的是,不同的项目使用不同的命名策略。有时项目名称包含在 artifactId 中,有时不包含。最后,Maven 模块被版本化。

A module in the Java module system doesn’t have a groupId, and doesn’t use version information. For public modules, it is recommended to include the reverse domain name of the project in the module name. In any case, the Maven module name, the Java module system module name, and the Maven artifact name will likely be somewhat related, but not the same. Figure 11-1 describes this.

Java 模块系统中的模块没有 groupId,也没有使用版本信息。对于公共模块,建议在模块名称中包含项目的反向域名。虽然,在任何情况下,Maven 模块名称、Java 模块系统模块名称以及 Maven 工件名称可能存在某些关联,但并不相同。图 11-1 描述了这一点。

Artifact naming

Adding dependencies also requires a two-step approach. First, a dependency needs to be added to the Maven artifact that represents the module, using its Apache Maven coordinates in the form of groupname:artifactname:version. This isn’t any different than it was for Apache Maven in a pre–Java module system world. Second, the dependency needs to be added as a requires statement in module-info.java to make the types exported by that module available to your code. If you didn’t add the dependency in the POM file, the compiler would fail on the requires statement because the module couldn’t be found. If you didn’t add the dependency to module-info.java, the dependency would remain effectively unused.

添加依赖项还需要完成一个两步法。首先,需要将依赖项添加到表示该模块的 Maven 工件中,以 groupname:artifactname:version 的形式使用其 Apache Maven 坐标。这与在 Java 模块系统之前的系统中使用 Apache Maven 没有什么不同。其次,在 module-info.java 中将依赖项作为 requires 语句添加,以便代码可以使用该模块导出的类型。如果没有在 POM 文件中添加依赖项,则编译器将在 requires 语句上失败,因为找不到该模块。但如果没有将依赖项添加到 module-info.java,那么依赖项仍然不会被使用。

The fact that we reference the dependency in two places also makes it possible that the name of a module isn’t necessarily the same as the Apache Maven group:artifact:version coordinate. A dependency may or may not be an explicit module. If no module-info.class is found, the dependency becomes an automatic module. This is transparent to the user: there is no difference in using an explicit module or automatic module from the perspective of an Apache Maven user.

以上两处引用依赖项的事实说明模块名称不一定与 Apache Maven group:-artifact:version 坐标相同。依赖项可能是也可能不是显式模块。如果找不到 module-info.class,则依赖项变成一个自动模块。这一切对用户是透明的:从 Apache Maven 用户的角度来看,使用显式模块或自动模块没有任何区别。

We will look at a complete code example of a multimodule project in the next section.

在下一节中将介绍一个多模块项目的完整代码示例。

11.1.1 Multimodule Projects 多模块项目

Before the Java module system, it was already common practice to create multimodule projects with Apache Maven. Even without the much stronger constraints that the Java module system brings, this is a great start for modular projects. Each module in a multimodule project has its own POM, a Maven-specific build descriptor in XML format. In the POM, the module’s dependencies are configured. This includes dependencies to external libraries as well as dependencies to other modules in the project. Every type used in a module must be part of the module itself, the JDK, or an explicitly configured dependency. Conceptually, this is not very different from what you’ve seen with the Java module system.

在 Java 模块系统之前,通常使用 Apache Maven 创建多模块项目。即使没有 Java 模块系统带来的强大约束,这也是模块化项目的一个良好的开始。多模块项目中的每个模块都有自己的 POM,这是一种 XML 格式的特定于 Maven 的构建描述符。在 POM 中配置了模块的依赖关系,包括对外部库的依赖以及对项目中其他模块的依赖。模块中使用的每种类型都必须是模块本身、JDK 或显式配置依赖项的一部分。从概念上讲,这与 Java 模块系统所看到的没有什么不同。

Although multimodule projects are common with Apache Maven, you might wonder what a module exactly is in a pre–Java 9 world. The representation of a module is a JAR file, which is the common artifact produced by Apache Maven. At compile-time, Maven configures the classpath such that it contains only the JAR files that are configured as dependencies. This way, it can emulate similar behavior as what the Java module system enforces by using requires in a module descriptor.

尽管多模块项目在 Apache Maven 中很常见,但你可能想知道 Java 9 之前的模块到底是什么样的。一个模块的表示方式为一个 JAR 文件,这是 Apache Maven 生成的常见工件。在编译时,Maven 配置类路径,使其仅包含被配置为依赖项的 JAR 文件。通过这种方式可以模拟 Java 模块系统在模块描述符中使用 requires 的类似行为。

Without the Java module system, Apache Maven doesn’t support strong encapsulation of packages. If a dependency is configured to another module, every type in that module can be read.

由于没有 Java 模块系统,因此 Apache Maven 不支持包的强封装。如果将依赖关系配置到另一个模块,则可以读取该模块中的每个类型。

11.1.2 EasyText with Apache Maven 使用 Apache Maven 创建 EasyText 示例

This section walks through migrating EasyText to Maven, the example application that we introduced in Chapter 3. The code itself is unchanged and will not be listed here.

本节将 EasyText 示例迁移到 Maven,该示例是第 3 章所介绍的示例应用程序。代码本身没有改变,因此在这里不再一一列出。

First of all, the EasyText directory structure is changed to conform with the standard Apache Maven directory structure. Each module has its own directory, with an src/main/java directory that contains the module’s source files (including module-info.java), and pom.xml at the root of the module. Also note the pom.xml at the root of the project. This is a parent POM that makes it possible to compile all the modules with a single command. Here’s the directory structure:

首先,将 EasyText 目录结构更改为符合标准的 Apache Maven 目录结构。每个模块都有自己的目录,包含模块源文件(包括 moduleinfo.java)的 src/main/java 目录以及模块根目录下的 pom.xml。其中要注意项目根目录下的 pom.xml,这是一个父 POM,可以用一个命令编译所有的模块。该目录结构如下:

  1. ├── algorithm.api
  2. ├── pom.xml
  3. └── src
  4. └── main
  5. └── java
  6. ├── algorithm.coleman
  7. ├── pom.xml
  8. └── src
  9. └── main
  10. └── java
  11. ├── algorithm.kincaid
  12. ├── pom.xml
  13. └── src
  14. └── main
  15. └── java
  16. ├── algorithm.naivesyllablecounter
  17. ├── pom.xml
  18. └── src
  19. └── main
  20. └── java
  21. ├── algorithm.nextgensyllablecounter
  22. ├── pom.xml
  23. └── src
  24. └── main
  25. └── java
  26. ├── cli
  27. ├── pom.xml
  28. └── src
  29. └── main
  30. ├── java
  31. └── resources
  32. ├── gui
  33. ├── pom.xml
  34. └── src
  35. └── main
  36. └── java
  37. └── pom.xml

The parent POM contains references to its subprojects, the actual modules. It also configures the compiler plug-in to use Java 9. Example 11-1 is a snippet with the most interesting parts of the pom.xml file.

父 POM 包含对其子项目的引用,即实际的模块,其还将编译器插件配置为使用 Java 9。示例 11-1 是一个包含 pom.xml 文件最有趣部分的代码片段。

Example 11-1. pom.xml (➥ chapter11/multi-module)

示例 11-1:pom.xml(chapter11/multi-module)

  1. <modules>
  2. <module>algorithm.api</module>
  3. <module>algorithm.coleman</module>
  4. <module>algorithm.kincaid</module>
  5. <module>algorithm.naivesyllablecounter</module>
  6. <module>algorithm.nextgensyllablecounter</module>
  7. <module>gui</module>
  8. <module>cli</module>
  9. </modules>
  10. <build>
  11. <pluginManagement>
  12. <plugins>
  13. <plugin>
  14. <groupId>org.apache.maven.plugins</groupId>
  15. <artifactId>maven-compiler-plugin</artifactId>
  16. <version>3.6.1</version>
  17. <configuration>
  18. <release>9</release>
  19. </configuration>
  20. </plugin>
  21. </plugins>
  22. </pluginManagement>
  23. </build>

Note that the modules section isn’t new and isn’t directly related to the Java module system. The modules themselves all have their own pom.xml file as well. In it, the module’s Apache Maven coordinates are specified (group name, artifact name, and version), as well as its dependencies. Let’s take a look at two of them, easytext.algorithm.api and easytext.algorithm.kincaid. The API module doesn’t have any dependencies, so its pom.xml is straightforward, as shown in Example 11-2.

请注意,modules 部分并不是新的,与 Java 模块系统没有直接关系。模块本身也有自己的 pom.xml 文件,其中指定了模块的 Apache Maven 坐标(组名、工件名称和版本)及其依赖关系。接下来看看其中的两个:easytext.algorithm.api 和 easytext. algorithm.kincaid。API 模块没有任何依赖关系,所以它的 pom.xml 很简单,如示例 11-2 所示。

Example 11-2. pom.xml (➥ chapter11/multi-module/algorithm.api)

示例 11-2:pom.xml(chapter11/multi-module/algorithm.api)

  1. <parent>
  2. <groupId>easytext</groupId>
  3. <artifactId>parent</artifactId>
  4. <version>1.0-SNAPSHOT</version>
  5. </parent>
  6. <artifactId>algorithm.api</artifactId>
  7. <name>Algorithm API</name>

In its module-info.java, the module is defined as in Example 11-3.

在其 module-info.java 中,模块定义如示例 11-3 所示。

Example 11-3. module-info.java (➥ chapter11/multi-module/algorithm.api)

示例 11-3:mudule-info.java(chapter11/multi-module/algorithm.api)

  1. module easytext.algorithm.api {
  2. exports javamodularity.easytext.algorithm.api;
  3. }

Note that technically the group/artifact names are not tied to the module name specified in the module’s module-info.java. They could be completely different. In any case, just remember that when you’re creating a dependency in a pom.xml file, you will need to use the Apache Maven coordinates. When you require a module in module-info.java, you use the name specified in the other module’s module-info.java; the Apache Maven coordinates don’t play any role on that level. Moreover, also notice that the directory name is not required to be the same as the module name.

请注意,从技术上讲,组/工件名称与模块的 module-info.java 中所指定的模块名称无关,它们可能完全不同。但不管怎样,只要记住当在 pom.xml 文件中创建一个依赖时,就需要使用 Apache Maven 坐标。当在 module-info.java 中 requires 一个模块时,使用在另一个模块的 module-info.java 中所指定的名称。Apache Maven 坐标在这个级别上不起任何作用。而且,还要注意目录名不要求与模块名相同。

Running a build will produce target/algorithm.api-1.0-SNAPSHOT.jar.

运行程序,生成 target/algorithm.api-1.0-SNAPSHOT.jar。

Now let’s move on to a module that uses the easytext.algorithm.api. In this case, we will have to add a dependency in the module’s pom.xml, and add a requires statement in its module-info.java, as shown in Example 11-4.

接下来介绍一个使用了 easytext.algorithm.api 的模块。此时,必须在模块的 pom.xml 中添加一个依赖项,并在 module-info.java 中添加一个 requires 声明,如示例 11-4 所示。

Example 11-4. pom.xml (➥ chapter11/multi-module/algorithm.kincaid)

示例 11-4:pom.xml(chapter11/multi-module/algorithm.kincaid)

  1. <groupId>easytext</groupId>
  2. <artifactId>algorithm.kincaid</artifactId>
  3. <packaging>jar</packaging>
  4. <version>1.0-SNAPSHOT</version>
  5. <name>algorithm.kincaid</name>
  6. <parent>
  7. <groupId>easytext</groupId>
  8. <artifactId>parent</artifactId>
  9. <version>1.0-SNAPSHOT</version>
  10. </parent>
  11. <dependencies>
  12. <dependency>
  13. <groupId>easytext</groupId>
  14. <artifactId>algorithm.api</artifactId>
  15. <version>${project.version}</version>
  16. </dependency>
  17. </dependencies>
  18. </project>

In module-info.java, we see the expected requires, as shown in Example 11-5.

在 module-info.java 中,可以看到所期望的 requires,如示例 11-5 所示。

Example 11-5. module-info.java (➥ chapter11/multi-module/algorithm.kincaid)

示例 11-5:module-info.java(chapter11/multi-module/algorithm.kincaid)

  1. module easytext.algorithm.kincaid {
  2. requires easytext.algorithm.api;
  3. provides javamodularity.easytext.algorithm.api.Analyzer
  4. with javamodularity.easytext.algorithm.kincaid.KincaidAnalyzer;
  5. uses javamodularity.easytext.algorithm.api.SyllableCounter;
  6. }

Removing either the dependency in pom.xml or the requires in module-info.java results in a compilation error. The exact reasons are subtly different. Removing the dependency from pom.xml results in the following error:

删除 pom.xml 中的依赖项或 module-info.java 中的 requires 都会导致编译错误。具体的原因略微不同。从 pom.xml 中删除依赖项会导致以下错误:

  1. module not found: easytext.algorithm.api

Removing the requires statement results in the following error:

删除 requires 语句将导致以下错误:

  1. package javamodularity.easytext.algorithm.api is not visible

As discussed previously, Apache Maven configures only the module path. An Apache Maven dependency works at a different level than a requires statement in module-info.java.

如前所述,Apache Maven 只配置模块路径。Apache Maven 依赖项的工作方式与 module-info.java 中的 requires 语句不同。

If you’ve used Apache Maven before, the pom.xml files should look familiar. No new syntax or configuration is required in Apache Maven when it comes to working with the Java module system.

如果以前使用过 Apache Maven,那么 pom.xml 文件应该看起来很熟悉。Apache Maven 在使用 Java 模块系统时不需要新的语法或配置。

This example shows that a properly modularized Apache Maven application is easy to migrate to the Java module system. Essentially, the addition of module-info.java files is all that’s required. In return, we get encapsulation and a much stronger run-time model.

该示例表明,一个正确模块化的 Apache Maven 应用程序很容易迁移到 Java 模块系统。从本质上来说,唯一需要做的是添加 module-info.java 文件。而作为回报,其将得到封装和更强大的运行时模型。

11.1.3 Running a Modular Application with Apache Maven 使用 Apache Maven 运行模块化的应用程序

We have our example project configured to be built by Apache Maven, but how do we run it? Maven is only a build tool and doesn’t have a role at run-time. Maven builds the artifacts we want to run, but in the end we still have to configure the Java runtime to run with the correct module path and/or classpath.

虽然示例项目被配置为使用 Apache Maven 进行构建,但如何运行它呢?Maven 只是一个构建工具,在运行时没有任何作用。Maven 构建了想要运行的工件,但是最后仍然需要配置 Java 运行时,以便运行正确的模块路径和类路径。

Configuring the module path manually is a lot easier than the classpath, but it would still be duplicate work because the information is in the pom.xml files already. Maven has an exec plug-in that helps with this process. Remember that this configures only the module path; it doesn’t have a run-time presence. The module path will be configured based on the dependencies listed in pom.xml. We need to configure the plug-in only with a module and main class to execute. Example 11-6 provides the configuration for the CLI module.

虽然手动配置模块路径比类路径要容易得多,但它仍然是重复的工作,因为相关信息已经在 pom.xml 文件中了。Maven 有一个帮助完成该过程的 exec 插件。请记住,该插件仅配置了模块路径,在运行时并不存在。模块路径将根据 pom.xml 中列出的依赖项进行配置。只需要配置一个模块和主类来执行插件即可。示例 11-6 提供了 CLI 模块的配置。

Example 11-6. pom.xml (➥ chapter11/multi-module/algorithm.cli)

示例 11-6:pom.xml(chapter11/multi-module/algorithm.cli)

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.codehaus.mojo</groupId>
  5. <artifactId>exec-maven-plugin</artifactId>
  6. <version>1.6.0</version>
  7. <executions>
  8. <execution>
  9. <goals>
  10. <goal>exec</goal>
  11. </goals>
  12. </execution>
  13. </executions>
  14. <configuration>
  15. <executable>${JAVA_HOME}/bin/java</executable>
  16. <arguments>
  17. <argument>--module-path</argument>
  18. <modulepath/>
  19. <argument>--module</argument>
  20. <argument>easytext.cli/javamodularity.easytext.cli.Main</argument>
  21. <argument>${easytext.file}</argument>
  22. </arguments>
  23. </configuration>
  24. </plugin>
  25. </plugins>
  26. </build>

We can execute the plug-in by using the exec command to start the application:

通过使用 exec 命令来启动应用程序,从而运行该插件:

  1. mvn exec:exec

11.2 Gradle

At the time of writing, unfortunately, Gradle has no official Java module system support yet. Support is expected and will probably be similar to Maven’s. When it comes to modularizing code, Gradle is already in excellent shape. Support for multimodule projects is good, which is a great start to prepare for the Java module system.

不幸的是,在编写本书时 Gradle 还没有提供官方的 Java 模块系统支持。即使提供支持,其方式可能会类似于 Maven。在模块化代码方面,Gradle 已经非常优秀了。对多模块项目的支持是很好的,而这恰恰是准备使用 Java 模块系统的一个很好的开端。

11.3 IDEs

IDEs such as IntelliJ, Eclipse, and NetBeans all have support for the Java module system, even before the official release of Java 9. The most important feature for an IDE to support the Java module system is understanding requires and exports in module-info.java files. These keywords control what types are available to a module, and an IDE should use this for syntax completion, pointing out errors, and suggestions for module dependencies. All three IDEs support this. This is closely related to the way Java modules map to projects, workspaces, and modules in IDEs. Each IDE has its own structure, and Java modules have to be mapped to this structure.

即使在 Java 9 正式发布之前,IntelliJ、Eclipse 和 NetBeans 等 IDE 也都支持 Java 模块系统。支持 Java 模块系统的 IDE 的最重要特性是理解 module-info.java 文件中的 requires 和 exports。这些关键字控制模块可用的类型,IDE 应该使用它来完成语法,指出错误,并提供模块依赖关系的建议。上面所提到的三个 IDE 都支持这一点。这与 Java 模块映射到 IDE 中的项目、工作区和模块的方式密切相关。每个 IDE 都有自己的结构,而 Java 模块必须映射到这个结构。

In Eclipse, each project represents a module, assuming it contains a module-info.java. As always, projects are grouped in a workspace. Both IntelliJ and NetBeans already had their own concept of a module, and this now maps directly to Java module system modules.

在 Eclipse 中,每个项目都代表一个模块,假设它包含一个 module-info.java。一如既往,项目被分组在一个工作区中。IntelliJ 和 NetBeans 都已经有了自己的模块概念,现在可以直接映射到 Java 模块系统模块。

Editing of module-info.java files is also supported by all three IDEs. This includes error highlighting and syntax completion on module names. Some IDEs even support showing a visual module graph based on a module descriptor.

上述三个 IDE 也支持编辑 module-info.java 文件,包括模块名称的错误突出显示和语法完成。一些 IDE 甚至支持基于模块描述符的可视化模块图显示。

Although this should be mostly transparent to users, clearly some duplication exists in IDEs when it comes to managing project structure. The IDEs have their own internal representation of modules (or projects, in the case of Eclipse). In the past, this model could be synchronized with an external model such as Maven or Gradle. The Java module system model is now a third level of module representation. Although the tools will hide this fact, it can still become somewhat confusing when you dig deeper. Figure 11-2 explains how both Maven and module-info.java are used to configure a project within the IDE. The same will likely be true for Gradle in the future.

虽然这一切对于用户来说应该是透明的,但是在管理项目结构时,IDE 中显然存在一些重复。IDE 有自己的模块内部表示(比如说 Eclipse 中的项目)。过去,该模型可以与 Maven 或 Gradle 等外部模型同步。现在,Java 模块系统模型是模块表示的第三级。虽然这些工具掩盖了这个事实,但是当深入挖掘时,仍然会变得有点混乱。图 11-2 解释了如何使用 Maven 和 module-info.java 在 IDE 中配置项目。对于未来的 Gradle 也是如此。

Configuring visibility in the IDE

In future releases of tools, we can expect to see much better support for refactoring, hints, and migration to modules.

在将来的工具版本中,会更好地支持重构、提示以及向模块的迁移。