6

一般来说,一组代码(客户端代码)链接到另一组代码(API 代码)。Java 链接通常在编译时在 .java 和 .class 之间或在运行时在 .class 和 .class 之间进行验证。然而,在后一种情况下,验证是在遇到错误引用时进行的(即它是惰性的)。

有没有办法使用编译后的代码一次强制验证客户端代码和 API 代码之间的所有链接?目的是验证客户端代码是否可以与给定版本的 API 一起工作——即使它已经针对另一个版本进行了编译。

(当然一种方法是对 API 进行反编译和重新编译,但有更直接的方法吗?)

4

6 回答 6

1

由于语言的性质和 JVM 的实现,链接的强制验证很困难。

我相信这个问题的基本原理是防止在运行时出现链接错误,这样做的意图非常有效。但是,如果从JVM的角度来看链接错误的原因,那么在不影响性能的情况下强制执行验证或多或少是困难的。

链接错误在运行时抛出,当 JVM 执行与方法调用指令对应的字节码时。JVM 字节码验证器的延迟最终传递通常是在此时启动,这可能会导致链接错误。不用说,从性能的角度来看,这是昂贵的。

(我的假设是)大多数项目(包括商业项目)因此避免强制验证,而是依赖构建和依赖管理系统来避免痛苦。在这个 SO question中有更多评论;选择 OSGi 框架的答案可能会有所帮助。

于 2010-07-28T19:30:28.237 回答
0

这个问题Alfresco Wiki中汲取灵感,您可以尝试-Xcomp启动一个测试 JVM 并预编译类以检查是否存在链接错误。

于 2010-08-09T12:09:52.137 回答
0

也许您可以针对 ClassPath 中的 jar 指定的 API 运行 junit 测试,然后只需为不同版本的 api 切换 jar 并再次运行测试。您将能够轻松地自动执行此操作。

于 2010-07-28T18:43:55.460 回答
0

可以通过自反性分析来自 java 类的代码。请参阅包java.reflect。一些分析工具使用此功能来获取有关已编译代码的信息。最好的例子可能是FindBugs

这个 API 作为限制,我认为你不能用它做你想做的事。如果在方法中调用了依赖项,则反射 API 可以找到该方法及其参数,但无法为您提供该方法中使用的依赖函数。

所以我认为Java中不存在这样的分析工具。

一种解决方案是一次性提供代码及其所有依赖项。在开发中,像 Maven 这样的生命周期管理工具可以帮助您管理项目的依赖关系。

于 2010-07-28T18:58:14.680 回答
0

我建议使用诸如 asm 之类的字节码工具来“访问”代码,并让您的访问者覆盖visitMethodInsn。然后在所有者类上使用反射来寻找具有指定名称和签名的方法。您还需要查看调用指令的操作码——它将是invokevirtual、invokeinterface、invokespecial 和invokestatic 之一。注意要注意invokevirtual和invokeinterface的区别;调用invokevirtual不会成功调用接口方法,调用invokeinterface 也不会成功调用未在接口上定义的方法。

于 2010-08-09T19:12:29.197 回答
0

对于您的需要,您可以使用 JarJarDiff[1] 之类的工具并获取新旧版本 API jar 之间的差异。然后将任务转换为验证您没有使用任何不兼容的 API。虽然不是自动的,但这种方法会引起您对更改的注意,而不仅仅是二进制兼容性。

如果您只想检查二进制兼容性,最简单的方法是针对新 JAR 重新编译项目。更困难(也更脆弱)的是扫描类路径并调用每个类的每个方法,寻找链接异常。请注意,这种幼稚的方法不会测试所有可能的路径并且几乎没有好处。

[1] http://depfind.sourceforge.net/tasks/jarjardiff.html

于 2010-08-04T14:52:42.613 回答