【问题标题】:Compile Module that Depends on an External Jar编译依赖于外部 Jar 的模块
【发布时间】:2018-11-11 05:22:15
【问题描述】:

我在 Java 11.0.1 中使用了 simple example using Project Jigsaw,在 Ubuntu 18.04 上使用 oracle JDK 11 构建。

按照这个例子,我创建了一个简单的项目,它编译成一个模块,将模块打包到一个 jar 中,然后使用jlink 创建一个独立的发行版。一切正常——最终结果是一个小型文件夹,其中包含一个精简的 JRE 和我的模块。

该项目仅由三个文件和一些文件夹组成:

.:
build.sh  src

./src:
com  module-info.java

./src/com:
greetings

./src/com/greetings:
Main.java

src/com/greetings/Main.java

package com.greetings;

public class Main {
   public static void main(String[] args) {
      System.out.println("Greetings!");
   }
}

src/module-info.java

module com.greetings { }

build.sh

#/bin/bash

#clean up from last build
rm -rf greetingsapp mlib mods

#compile
javac -d mods/com.greetings src/module-info.java src/com/greetings/Main.java

#Make module jar
mkdir mlib
jar --create --file=mlib/com.greetings.jar --main-class=com.greetings.Main -C mods/com.greetings .

#build distribution
jlink --module-path /usr/lib/jvm/java-11-oracle/jmods/:mlib --add-modules com.greetings --output greetingsapp --strip-debug --no-header-files --no-man-pages --launcher greetings=com.greetings

#run
greetingsapp/bin/greetings

所有这些都有效。现在问题来了:

接下来我要做的是使用外部库,所以我在 Main.java 中添加了几行:

Main.java - 更新

package com.greetings;

import org.apache.commons.cli.CommandLine; //new line

public class Main {

   CommandLine line; //new line

   public static void main(String[] args) {
      System.out.println("Greetings!");
   }
}

然后我将commons-cli-1.4.jar 放在一个名为lib 的新目录中。

创建此文件结构的人:

.:
build.sh  lib  src

./lib:
commons-cli-1.4.jar

./src:
com  module-info.java

./src/com:
greetings

./src/com/greetings:
Main.java

我修改了编译行以在类路径中包含 commons jar:

javac -cp lib/commons-cli-1.4.jar:. \
-d mods/com.greetings \
src/module-info.java src/com/greetings/Main.java

但是,当我尝试编译它时,我得到了这个错误:

src/com/greetings/Main.java:10: error: package org.apache.commons.cli is not visible
import org.apache.commons.cli.CommandLine;
                     ^
   (package org.apache.commons.cli is declared in the unnamed module, but module org.apache.commons.cli does not read it)
1 error

如何修改我的项目以便可以针对 commons-cli-1.4.jar 进行编译?


编辑,在用户 nullpointer 的建议下,我尝试将 -cp 标志更改为仅 -p 标志,因此将外部 jar 添加到模块路径中。不幸的是,这也行不通。以下是我尝试过的各种 javac 命令也不起作用:

javac -p lib -d mods/com.greetings \
src/module-info.java src/com/greetings/Main.java

javac --module-path=lib -d mods/com.greetings \
src/module-info.java src/com/greetings/Main.java

javac -p lib/commons-cli-1.4.jar -d mods/com.greetings \
src/module-info.java src/com/greetings/Main.java

【问题讨论】:

  • 如果您已将 jar 指定在模块路径上并将其从类路径中删除,则理想情况下它不应保留在未命名的模块中。你能用你的新 javac 命令行更新这个问题吗?
  • 确保您的模块声明现在需要该模块 ...尝试一下,注意到commons-cli:commons-cli:1.4 的模块名称需要requires commons.cli;,你能看看这个?
  • 您这样做是为了学习还是为了完成任务?对于实际使用的工作,采用 Maven 还是 Gradle?
  • Chrylis:现在学习。下一步是转换一个现有的大型项目,我现在正在熟悉构建模块。每次我在那里遇到问题时,我都会把它提炼到这个测试环境中,理解它,然后将它应用到大型项目中。该项目目前使用 Ant,但我可能正在过渡到 Gradle。
  • @JoshuaD 将jlink 与自动模块一起使用的最后一步恐怕是我到目前为止还没有看到人们采用的方法。除此之外,其余部分应该可以正常工作。我尝试了您的设置并且可以使用它,因此made an answer。

标签: java javac java-module java-11 jlink


【解决方案1】:

您已将 jar 放在类路径中,因此它会生成 unnamed module.。

未命名的模块导出其所有包。 ...

但这并不意味着命名模块中的代码可以访问未命名模块中的类型。 ...

这个限制是有意的,因为允许命名模块依赖于类路径的任意内容会使 可靠的配置是不可能的。

尝试将相同的 jar 放在 modulepath 上,从那里可以推断出它是 automatic module。


您还需要确保相应更新模块的模块声明,以定义对新添加模块的依赖以访问其导出的包。

module com.greetings { 
    requires commons.cli;
}

编辑:在您的情况下尝试完整的 build.sh 仍然会失败,但是 链接步骤,because of the presence of an automatic module.

【讨论】:

  • 1.您是如何确定名称 commons.cli 的?我的实际项目中有 14 个外部 jar。 2.你强调的jlink/external jar问题有没有解决方案,还是无法解决?
  • 1.使用jar --file=<> --describe-module command。 2. 我认为这是有意限制的,以确保在使用 jlink 创建独立运行时环境时仅使用显式模块(命名模块)或简单术语模块化项目。 |另外,注意 14 jars 使用命令行不是一个好的选择,你应该使用像 chrylis in comments as well. 建议的 Maven/Gradle 这样的框架@
  • 所以 jlink 对于依赖 14 个尚未更新为模块的外部 jar 的项目来说不是一个好的选择?还有另一种创建精简 JRE 的方法吗?
  • 我可以在这里找到有关如何转换我的 jar 依赖项的示例:github.com/codetojoy/easter_eggs_for_java_9/blob/master/… 这有点麻烦,但对我来说已经足够了。
猜你喜欢
  • 1970-01-01
  • 2013-11-05
  • 1970-01-01
  • 2015-11-10
  • 1970-01-01
  • 2012-12-25
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多