java:在jar版本

时间:2016-11-14 13:03:02

标签: java jar compatibility

假设我们有一组项目“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”异常。

2 个答案:

答案 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)

  1. 使用jar x
  2. 打开旧包装和新包装的包装
  3. 使用javap
  4. 获取课程内容
  5. 比较两个罐子里的内容
  6. 例如,如果当前目录中有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
    

    当然,这不是完全自动化的方法,你仍然应该手动检查差异输出。不过,这比没有更好。