Maven/Retrolambda:如何检测对Java 8类的依赖

8

背景:

我们有一个基于maven的Java项目,目标是JRE 1.7,但源代码使用了lambda表达式,因此我们使用retrolambdaJava 8的源代码转换为Java 7。在需要使用streams、function.*、Optional等时,我们还使用StreamSupport backport库。

使用retrolambda需要将项目的源代码和目标语言级别均配置为1.8。

如果没有依赖于java8类或方法(例如java.util.stream.*java.util.Optional或在java8中引入的Collection.forEach之类的方法),则一切正常。如果存在这样的用法,则构建通过,但在运行时,在Java 8的JVM下运行时会失败。

问题:

我的目标是在存在这种依赖关系的情况下使构建失败。是否有一种方法可以在构建时检测对新的Java 8类/方法的依赖关系?

我考虑了两个可能的选项,但我不确定是否可行:

  1. 某种字节码分析器,用于检测预定义类和方法的依赖关系。是否有这样的工具/maven插件?
  2. Lint (lint4j)规则。不确定是否可以使用lint检测到对类/方法的依赖关系

3
在编译时只需更改引导类路径,指向Java 7安装包中的rt.jar即可。为了让编译器能够使用Lambda表达式,您可能需要将一个虚拟的JAR文件添加到路径中,其中包含一个LambdaMetaFactory类及其两个方法的声明,以防编译器进行验证。这些方法不必起作用,因为您最终会使用retrolambda处理已编译的代码(然后使用实际的JRE8)。 - Holger
2
按照Holger所说,这种方法对我起作用了:在JRE7的“rt.jar”中添加LambdaConversionExceptionLambdaMetafactorySerializedLambda的桩代码(在我的情况下,使用额外的虚拟包并没有奏效。我收到了“致命错误:无法在类路径或引导类路径中找到java.lang包”的消息)。然后通过“<bootclasspath>`”标签将maven-compiler-plugin指向增强版的“rt.jar”。作为测试,我编译了streamsupport源文件(sans j8.u.DelegatingSpliterator,它使用Java 8 API,因此不能用Java 7的“rt.jar”进行编译)。 - Stefan Zobel
一种方法可以是使用JRE 7来运行你的测试套件。如果使用Java 8的API,应该会抛出异常。 - Joseph Earl
3
当然,但是原帖的问题是如何在构建时检测这个问题。 - apophis
通常情况下,@apophis,测试是作为整个构建生命周期的一部分运行的。 - Joseph Earl
2
@JosephEarl 你说得对 - 测试是构建周期的一部分,但这个解决方案的问题在于测试永远无法达到100%的覆盖率。这就是为什么我更喜欢基于静态分析而不是运行代码的解决方案。 - Denis Itskovich
1个回答

5
你可以使用Animal Sniffer Maven插件来实现这个功能。它允许你检查你的代码是否只使用了指定基线(称为“签名”)的API。在你的情况下,你需要使用org.codehaus.mojo.signature:java17:1.0签名。
正如其他人所指出的,你也可以设置引导类路径,但是这将需要设置JDK 7,并且会使构建过程变得更加复杂,因为你需要指向JDK 7安装位置。根据我的经验,Animal Sniffer要容易得多。

好的,很高兴听到这个消息。 - Gunnar

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