Scala Maven Plugin 编译找不到 javac 异常分析


1. 问题现象

在 IDEA 中执行 Maven compile 时,项目编译失败。项目是一个 Maven + Scala + Java 混合项目,使用的是 scala-maven-plugin 编译 Scala 代码。

执行命令中可以看到当前使用的是 JDK 1.8:

D:\ProgramFiles\Java\jdk1.8.0_341\bin\java.exe

Maven 使用的是:

D:\ProgramFiles\apache-maven-3.6.1

编译过程中先出现了一个 Maven settings 警告:

[WARNING] Some problems were encountered while building the effective settings
[WARNING] Unrecognised tag: 'blocked'
@ D:\ProgramFiles\apache-maven-3.6.1\conf\settings.xml, line 216, column 16

后面执行到 scala-maven-plugin 时失败:

[INFO] --- scala-maven-plugin:4.5.0:compile (default) @ wangba_archival ---
[INFO] Using incremental compilation using Mixed compile order
[INFO] compiling 32 Scala sources and 2 Java sources to D:\Documents\work\codes\dgzwb-archival\target\classes ...
[WARNING] javac exited with exit code -1
[ERROR] ## Exception when compiling 34 sources to D:\Documents\work\codes\dgzwb-archival\target\classes
java.io.IOException: Cannot run program "D:\ProgramFiles\Java\jdk1.8.0_341\jre\bin\javac"
(in directory "D:\Documents\work\codes\dgzwb-archival"):
CreateProcess error=2, 系统找不到指定的文件。

最关键的错误是这一句:

Cannot run program "D:\ProgramFiles\Java\jdk1.8.0_341\jre\bin\javac"
CreateProcess error=2, 系统找不到指定的文件。

2. 先判断哪个是主因

这段日志里有两个问题:

  1. Maven 提示 Unrecognised tag: 'blocked'
  2. Scala 编译时报 jre\bin\javac 找不到

真正导致构建失败的是第二个问题,也就是 javac 找不到。

Unrecognised tag: 'blocked' 只是 Maven 读取 settings.xml 时的警告。Maven 3.8.1 开始在 mirror 配置中增加了 <blocked> 参数,用来默认阻止外部 HTTP 仓库。当前环境使用的是 Maven 3.6.1,这个版本不认识 <blocked> 标签,所以会打印警告。

这个警告需要处理,但它不是这次 BUILD FAILURE 的直接原因。

3. 为什么会去找 jre\bin\javac

Oracle 的 Java 8 文档中说明,JDK 包含编译器、调试器等开发工具,而 JRE 主要用于运行 Java 程序。javac 属于 JDK 的编译工具。

正常情况下,javac 应该在:

D:\ProgramFiles\Java\jdk1.8.0_341\bin\javac.exe

而不是:

D:\ProgramFiles\Java\jdk1.8.0_341\jre\bin\javac

因为 JRE 目录下面通常只有运行环境,不应该依赖它提供 javac

这次异常中,Maven 启动时确实使用了:

D:\ProgramFiles\Java\jdk1.8.0_341\bin\java.exe

但是 scala-maven-plugin 在增量编译 Java 源码时,最终却调用到了:

D:\ProgramFiles\Java\jdk1.8.0_341\jre\bin\javac

说明插件内部或当前环境推导出来的 Java Home 路径不正确,把 jre 当成了查找 javac 的位置。

4. 为什么 Scala 项目会调用 javac

日志中有一行很关键:

Using incremental compilation using Mixed compile order

这说明当前项目是 Scala 和 Java 混合编译。scala-maven-plugin 不只是编译 Scala 文件,还会配合 Zinc 增量编译器处理 Java 源码。

日志里也明确写了:

compiling 32 Scala sources and 2 Java sources

所以即使项目看起来主要是 Scala,只要里面有 Java 源码,或者 Scala 编译过程中需要 Java 编译器参与,最终仍然需要 javac

如果当前环境里找不到正确的 javac,Scala 编译也会失败。

5. 解决方案一:检查 IDEA 的 Maven JDK

如果是在 IDEA 里执行 Maven,先检查 IDEA 的 Maven JDK。

路径一般是:

File -> Settings -> Build, Execution, Deployment -> Build Tools -> Maven -> Runner

重点检查:

JRE

这里不要选择 JRE,也不要选择项目里某个不完整的 Java 运行环境,应该选择完整的 JDK,例如:

D:\ProgramFiles\Java\jdk1.8.0_341

如果这里选成了:

D:\ProgramFiles\Java\jdk1.8.0_341\jre

就很容易出现 jre\bin\javac 找不到的问题。

6. 解决方案二:检查 JAVA_HOME 和 Path

在命令行中检查:

echo %JAVA_HOME%

期望输出是 JDK 根目录:

D:\ProgramFiles\Java\jdk1.8.0_341

再检查 javac 是否能直接执行:

javac -version

如果提示找不到 javac,需要检查系统环境变量:

JAVA_HOME=D:\ProgramFiles\Java\jdk1.8.0_341
Path=%JAVA_HOME%\bin

注意不要写成:

JAVA_HOME=D:\ProgramFiles\Java\jdk1.8.0_341\jre

JAVA_HOME 应该指向 JDK 根目录,而不是 JRE 目录。

7. 解决方案三:在 scala-maven-plugin 中显式指定 javac

如果 IDEA 和环境变量都没有问题,但 scala-maven-plugin 仍然推导错了路径,可以在插件配置中显式指定 javac

例如:

<plugin>
    <groupId>net.alchim31.maven</groupId>
    <artifactId>scala-maven-plugin</artifactId>
    <version>4.5.0</version>
    <configuration>
        <scalaVersion>2.11.8</scalaVersion>
        <recompileMode>incremental</recompileMode>
        <compileOrder>Mixed</compileOrder>
        <javacArgs>
            <javacArg>-source</javacArg>
            <javacArg>1.8</javacArg>
            <javacArg>-target</javacArg>
            <javacArg>1.8</javacArg>
        </javacArgs>
    </configuration>
</plugin>

如果项目中使用了 Maven Toolchains,也可以统一指定 JDK:

<toolchain>
    <type>jdk</type>
    <provides>
        <version>1.8</version>
        <vendor>oracle</vendor>
    </provides>
    <configuration>
        <jdkHome>D:\ProgramFiles\Java\jdk1.8.0_341</jdkHome>
    </configuration>
</toolchain>

老项目里更常见的处理方式还是先保证 IDEA、Maven、命令行使用的是同一个 JDK。

8. 处理 settings.xml 中的 blocked 警告

日志中还有一个警告:

Unrecognised tag: 'blocked'

这个一般是因为 settings.xml 中有类似配置:

<mirror>
    <id>maven-default-http-blocker</id>
    <mirrorOf>external:http:*</mirrorOf>
    <name>Pseudo repository to mirror external repositories initially using HTTP.</name>
    <url>http://0.0.0.0/</url>
    <blocked>true</blocked>
</mirror>

<blocked> 是 Maven 3.8.1 之后用于阻止外部 HTTP 仓库的配置。当前日志中的 Maven 是 3.6.1,所以它不认识这个标签。

解决方式有两种:

  1. 升级 Maven 到 3.8.1 或更高版本。
  2. 如果必须使用 Maven 3.6.1,就从 settings.xml 中删除不兼容的 <blocked> 配置。

如果公司内网仓库仍然是 HTTP 地址,不建议简单删除后不管。更稳妥的方式是把仓库地址改成 HTTPS,或者配置公司内部仓库代理。

9. 建议排查顺序

遇到这类问题,可以按下面顺序排查:

步骤 检查内容 说明
1 看最终失败原因 本例是 Cannot run program ... jre\bin\javac
2 检查 JDK 是否完整 确认 bin\javac.exe 存在
3 检查 IDEA Maven Runner 确认 JRE 选择的是 JDK 根目录
4 检查 JAVA_HOME 不要指向 jre
5 命令行执行 javac -version 确认系统能找到 javac
6 处理 Maven settings 警告 Maven 3.6.1 不支持 <blocked>

10. 总结

这次异常的直接原因是:

scala-maven-plugin 在混合编译 Scala 和 Java 源码时,需要调用 javac,
但是最终查找到了 jre\bin\javac,而这个路径下没有 javac。

真正的修复方向是:

让 IDEA、Maven、JAVA_HOME 都指向完整 JDK,而不是 JRE。

同时,settings.xml 中的 <blocked> 警告也应该顺手处理。它不是这次编译失败的直接原因,但说明 Maven 版本和配置文件格式不匹配,后面下载依赖时也可能继续引发问题。


文章作者: hnbian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hnbian !
评论
  目录