2010-07-28 49 views
6

一般来说,一组代码(客户端代码)与另一组代码(API代码)相链接。 Java链接通常在编译时在.java & .class之间或在运行时的.class & .class之间验证。然而,在后一种情况下,验证是在遇到不良引用时(即,它是懒惰的)。如何验证已编译的Java代码之间的链接?

有没有办法强制验证全部一次编译代码与客户端代码和API代码之间的链接?目的是验证客户端代码是否可以与给定版本的API一起工作 - 即使它已经被编译为另一个版本。

(当然,办法之一是反编译和重新编译针对API,但有一个更直接的方法是什么?)

回答

0

或许你可以对一个罐子在classpath中指定的API运行JUnit测试,然后只需将jar的不同版本换成api并再次运行测试。你可以很容易地自动化。

0

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

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

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

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

1

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

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

当JVM执行对应于method invocation instructions的字节码时,会在运行时引发链接错误。通常在这一点上,推迟的final pass of the JVM's bytecode verifier被踢入,这可能导致连接错误。不用说,从性能角度来看,这是昂贵的。

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

+0

性能不一定是一个主要问题,因为结果可以被记住。在某些情况下,代码量也不一定很大。 – 2010-07-28 20:12:00

+1

好的,很好。然后,您可能希望使用像ASM这样的字节码工程库(参考使用CheckClassAdapter)或BCEL(其中包含JustIce验证程序)在足够的情况下执行验证,或者在需要时扩展它们。我不确定Javassist是否有类似的功能。 – 2010-07-28 20:44:33

0

为了您的需要,您可以使用像JarJarDiff [1]这样的工具,并获取新版和旧版API瓶之间的差异。然后,该任务转变为验证您不使用任何不兼容的API。虽然不是自动的,但这种方法将注意力转移到了二进制兼容性上。

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

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

0

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