假设我们有一组项目“p1.jar”,“p2.jar”等,所有这些项目都使用了库“foo-1.0.0.jar”。
假设创建了新版本“foo-1.0.1.jar”。作为附加检查,所有项目p1,p2,...都使用新的foo-1.0.1.jar重新编译。不会出现编译错误。
现在,在生产环境中,foo-1.0.0.jar被foo-1.0.1.jar取代。没有更新p1.jar,p2.jar,...已完成。不幸的是,一切都崩溃了。
可以做一些其他检查以100%确定新库可以替换旧库吗?
显然,我们不是在谈论检查新库中引入的代码错误或功能的变化(例如,如果在新版本函数中“sum”执行减法而不是添加)。但至少要检查参数,结果,可用类等的变化。
一个例子是,foo-1.0.0.jar包含方法:
int m1() {
// some code
return 0; // always return 0, and ignored by the users
}
在foo-1.0.1中它改为:
void m1() {
// some code
}
不幸的是,该方法的结果是Java中的名称修改(不是在C中)的一部分,并且在查找“int m1()”时,p1.jar将失败并出现“NoSuchMethod”异常。
答案 0 :(得分:2)
您可以使用japicmp来比较新旧库存档以进行API更改。
但是仍然存在无法检测到您检查的库的依赖性的风险。
在下面找到一个示例来演示可能未检测到的更改。
<强> ApiClass1.java 强>
class ApiClass {
public static final int FOO = 23;
public static void version() {
System.out.println("version 1 FOO: " + FOO);
}
}
<强> ApiClass2.java 强>
class ApiClass {
public static final int FOO = 42;
public static void version() {
System.out.println("version 2 FOO: " + FOO);
}
}
<强> ApiDemo.java 强>
class ApiDemo {
public static void main(String...args) {
ApiClass.version();
System.out.println("ApiClass.FOO: " + ApiClass.FOO);
}
}
为API版本1编译和构建库
javac ApiClass1.java
jar cf api_v1.jar ApiClass.class
为API版本2编译和构建库
javac ApiClass2.java
jar cf api_v2.jar ApiClass.class
使用API v1编译,构建和运行代码
javac -cp api_v1.jar ApiDemo.java
java -cp api_v1.jar:. ApiDemo
输出
version 1 FOO: 23
ApiClass.FOO: 23
使用API v2运行代码,无需重新编译
java -cp api_v2.jar:. ApiDemo
version 2 FOO: 42
ApiClass.FOO: 23
唯一可靠的方法是针对新版本编译代码,运行所有单元/集成测试并检查它们是否通过。
答案 1 :(得分:1)
jar x
javap
例如,如果当前目录中有foo-1.0.0.jar和foo-1.0.1.jar,则可以运行此bash脚本:
# unpack old jar
mkdir foo-1.0.0
cd foo-1.0.0
jar xf ../foo-1.0.0.jar
# unpack new jar
mkdir ../foo-1.0.1
cd ../foo-1.0.1
jar xf ../foo-1.0.1.jar
# get unpacked classes contents
cd ..
for file in `find foo-1.0.0 foo-1.0.1 -name '*.class'`; do javap $file > $file.txt; done
# remove redundant .class files
find foo-1.0.0 foo-1.0.1 -name '*.class' | xargs rm
# compare jar contents
diff -r foo-1.0.0 foo-1.0.1
当然,这不是完全自动化的方法,你仍然应该手动检查差异输出。不过,这比没有更好。