1. Introduction
1.介绍
In this tutorial, we’re going to talk about an exception that Maven throws when misconfigured: JAVA_HOME should point to a JDK, not a JRE.
在本教程中,我们要讨论的是Maven在配置错误时抛出的一个异常。JAVA_HOME应指向JDK,而不是JRE.。
Maven is a powerful tool for building code. We’ll look under the hood to understand why this error happens and will see how to solve it.
Maven是一个构建代码的强大工具。我们将深入了解这个错误发生的原因,并看看如何解决这个问题。
2. The JAVA_HOME Problem
2.JAVA_HOME问题
After installing Maven, we have to set the JAVA_HOME environment variable, so the tool knows where to find the JDK commands to execute. Maven goals run the appropriate Java commands against the project’s source code.
安装Maven后,我们必须设置JAVA_HOME环境变量,以便工具知道在哪里找到要执行的JDK命令。Maven的目标是针对项目的源代码运行适当的Java命令。
For example, the most common scenario is to compile the code by executing the javac command.
例如,最常见的情况是通过执行javac命令来编译代码。
If JAVA_HOME is not pointing to a valid JDK installation, Maven will throw an error at every execution:
如果JAVA_HOME没有指向有效的JDK安装,Maven每次执行都会出现错误。
mvn -version
# Output...
The JAVA_HOME environment variable is not defined correctly
This environment variable is needed to run this program
NB: JAVA_HOME should point to a JDK, not a JRE
3. JDK or JRE
3.JDK或JRE
How does Maven verify the JAVA_HOME path?
Maven如何验证JAVA_HOME路径?
Before running any goals, Maven checks for the existence of the java command in the path specified by JAVA_HOME or by asking the OS for a default JDK installation. If the executable is not found, Maven terminates with the error.
在运行任何目标之前,Maven会检查java命令在JAVA_HOME指定的路径中是否存在,或者询问操作系统是否有默认的JDK安装。如果找不到可执行文件,Maven就会以错误结束。
Here is the mvn executable check for Linux (Apache Maven v3.5.4):
以下是Linux下的mvn可执行检查(Apache Maven v3.5.4)。
if [ -z "$JAVA_HOME" ] ; then
JAVACMD=`which java`
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
echo "The JAVA_HOME environment variable is not defined correctly" >&2
echo "This environment variable is needed to run this program" >&2
echo "NB: JAVA_HOME should point to a JDK not a JRE" >&2
exit 1
fi
This check may seem reasonable at first glance, but we have to consider that both JDK and JRE have a bin folder and both contain an executable java file.
这个检查乍一看似乎很合理,但我们必须考虑到JDK和JRE都有一个bin文件夹,都包含一个可执行的java文件。
Therefore, it’s possible to configure JAVA_HOME to point to a JRE installation, hiding this particular error and causing problems at a later stage. While the JRE’s main purpose is to run Java code, the JDK can also compile and debug among other important differences.
因此,有可能将JAVA_HOME配置为指向JRE安装,从而隐藏了这个特殊的错误,并在后期造成问题。虽然JRE的主要目的是运行Java代码,但JDK也可以编译和调试以及其他重要区别。
For this reason, an mvn compile command would fail – as we’ll see in the next subsection.
由于这个原因,mvn编译命令会失败–正如我们将在下一小节看到的。
3.1. Compilation Failure Because of JRE Instead of JDK
3.1.由于使用JRE而不是JDK而导致编译失败
As usual with default settings, they’re very helpful if we have a “standard” configuration.
像通常的默认设置一样,如果我们有一个 “标准 “配置,它们是非常有用的。
For example, if we install Java 11 on an Ubuntu 18.04 system and don’t set the JAVA_HOME environment variable, Maven will still happily find our JDK and use it for the different goals, including compiling.
例如,如果我们在Ubuntu 18.04系统上安装了Java 11,但没有设置JAVA_HOME环境变量,Maven仍然会愉快地找到我们的JDK,并使用它来实现不同的目标,包括编译。
But if we’ve managed to set up a non-standard configuration (let alone made a mess) on our system, Maven’s helpfulness doesn’t suffice anymore. It can be even misleading.
但如果我们设法在系统上设置了非标准的配置(更不用说搞得一团糟),Maven的帮助性就不再足够了。它甚至会产生误导。
Let’s assume we have the following configuration on Ubuntu 18.04:
让我们假设我们在Ubuntu 18.04上有以下配置。
- JDK 11
- JRE 8
- JAVA_HOME set to the path of the JRE 8 installation
If we do our basic check:
如果我们做基本的检查。
mvn --version
We’ll get a meaningful output like this:
我们会得到这样一个有意义的输出。
Apache Maven 3.6.0 (97c98ec64a1fdfee7767ce5ffb20918da4f719f3; 2018-10-24T18:41:47Z)
Maven home: /opt/apache-maven-3.6.0
Java version: 1.8.0_191, vendor: Oracle Corporation, runtime: /usr/lib/jvm/java-8-openjdk-amd64/jre
Default locale: en, platform encoding: UTF-8
OS name: "linux", version: "4.15.0-42-generic", arch: "amd64", family: "unix"
Let’s see what happens if we try to compile a project:
让我们看看如果我们尝试编译一个项目会发生什么。
mvn clean compile
Now, we get an error:
现在,我们得到一个错误。
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project my-app: Compilation failure
[ERROR] No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?
3.2. Fixing the Compilation Error on the Project Level
3.2.修复项目层面的编译错误
As in many other cases with Maven, it’s recommended to set up meaningful system-wide settings – in this case, we’ll change the value of the JAVA_HOME variable as described in section 5 to point to the JDK instead of the JRE.
与Maven的许多其他情况一样,建议设置有意义的全系统设置–在本例中,我们将按照第5节所述,改变JAVA_HOME变量的值,以指向JDK而不是JRE。
However, if we can’t set up defaults for whatever reason, we can still override the settings on the project level. Let’s see how to do that.
然而,如果我们由于某种原因无法设置默认值,我们仍然可以在项目层面上覆盖设置。让我们看看如何做到这一点。
First, we’ll open the pom.xml of our project, go to the section build / pluginManagement / plugins and have a look at the entry for the maven-compiler-plugin:
首先,我们打开项目的pom.xml,进入build / pluginManagement / plugins部分,看一下maven-compiler-plugin条目。
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
Then, we’ll add a configuration to it so that it uses a custom executable and skip searching for javac in the JAVA_HOME/bin directory:
然后,我们将给它添加一个配置,使它使用一个自定义的可执行文件,并跳过在JAVA_HOME/bin目录下搜索javac。
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<fork>true</fork>
<executable>/usr/lib/jvm/java-11-openjdk-amd64/bin/javac</executable>
</configuration>
</plugin>
On Unix systems, this executable should be a script with adequate permission. On Windows systems, it should be an .exe file.
在Unix系统上,这个可执行文件应该是一个有足够权限的脚本。在Windows系统上,它应该是一个.exe文件。
Next, we’ll try to compile the project again:
接下来,我们将尝试再次编译该项目。
mvn clean compile
Now, the build – including the compile phase with the maven-compiler-plugin – is successful.
现在,构建(包括使用maven-compiler-plugin的编译阶段)成功了。
4. Checking the JAVA_HOME Configuration
4.检查JAVA_HOME配置
It’s pretty simple to check if JAVA_HOME points to an actual JDK. We can either print its content in a terminal, or we can run one of the following shell commands:
检查JAVA_HOME是否指向一个实际的JDK非常简单。我们可以在终端中打印它的内容,或者运行下面的一个 shell 命令。
4.1. Checking JAVA_HOME on Linux
4.1.在Linux上检查JAVA_HOME
Just open a terminal and type:
只要打开一个终端,然后输入。
> $JAVA_HOME/bin/javac -version
If JAVA_HOME points to a JDK, the output should look like:
如果JAVA_HOME指向一个JDK,输出应该是这样的。
> javac 1.X.0_XX
If JAVA_HOME doesn’t point to a JDK, the OS will throw an error message:
如果JAVA_HOME没有指向一个JDK,操作系统将抛出一个错误信息。
> bash: /bin/javac: No such file or directory
4.2. Checking JAVA_HOME on Windows
4.2.在Windows上检查JAVA_HOME
Open a command prompt and type:
打开一个命令提示符并输入。
%JAVA_HOME%\bin\javac -version
If JAVA_HOME points to a JDK, the output should look like:
如果JAVA_HOME指向一个JDK,输出应该是这样的。
> javac 1.X.0_XX
If JAVA_HOME doesn’t point to a JDK, the OS will throw an error message:
如果JAVA_HOME没有指向一个JDK,操作系统将抛出一个错误信息。
> The system cannot find the path specified.
5. How to Solve the Issue
5.如何解决这个问题
First of all, we need to know where to find our JDK:
首先,我们需要知道在哪里可以找到我们的JDK。
- If we installed our JDK distribution using a package installer, we should be able to find the path using the OS search utility
- If the distribution was a portable one, let’s check the folder where we extracted it
Once we know the path to the JDK, we can set our JAVA_HOME environment variable, using the appropriate results for our particular OS.
一旦我们知道了JDK的路径,我们就可以设置我们的JAVA_HOME环境变量,使用适合我们特定操作系统的结果。
6. Conclusion
6.结论
In this brief tutorial, we’ve discussed the “JAVA_HOME should point to a JDK not a JRE” Maven error and examined its root cause.
在这个简短的教程中,我们讨论了”JAVA_HOME应指向JDK而非JRE”Maven错误,并研究了其根本原因。
Finally, we discussed how to check your JAVA_HOME environment variable, and how to make sure it points to a JDK.
最后,我们讨论了如何检查你的JAVA_HOME环境变量,以及如何确保它指向一个JDK。