Assume we have a set of projects "p1.jar", "p2.jar", etc, all them using library "foo-1.0.0.jar".
Assume a new version "foo-1.0.1.jar" is created. As an additional check, all projects p1, p2, ... are recompiled using new foo-1.0.1.jar. No compilation errors appears.
Now, in the production environment, foo-1.0.0.jar is replaced by foo-1.0.1.jar. No update of p1.jar, p2.jar, ... is done. Unfortunately, everything crashes.
It is possible to do some other checks to be 100% sure new library can replace old one?
Obviously, we are not talking about check of code errors introduced in new library or changes in the functionality (by example, if in new version function "sum" does a subtraction instead of an addition). But at least check changes in arguments, results, available classes, etc.
One example is, foo-1.0.0.jar contains method:
int m1() {
// some code
return 0; // always return 0, and ignored by the users
}
that in foo-1.0.1 it is changed to:
void m1() {
// some code
}
Unfortunately, the result of the method is part of the name mangling in Java (not in C) and p1.jar will fail with "NoSuchMethod" exception when looking for "int m1()".
You might use japicmp to compare the new and old library archive for API changes.
But there is still the risk that a dependency of the library you check would not be detected.
Find below an example to demonstrate changes which might be undetected.
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);
}
}
compile and build library for API version 1
javac ApiClass1.java
jar cf api_v1.jar ApiClass.class
compile and build library for API version 2
javac ApiClass2.java
jar cf api_v2.jar ApiClass.class
compile, build and run your code with API v1
javac -cp api_v1.jar ApiDemo.java
java -cp api_v1.jar:. ApiDemo
output
version 1 FOO: 23
ApiClass.FOO: 23
run your code with API v2, without recompilation
java -cp api_v2.jar:. ApiDemo
version 2 FOO: 42
ApiClass.FOO: 23
The only reliable way is to compile your code against the new version, run all your unit-/integration test and check if they pass.
jar xjavapFor example, if you have foo-1.0.0.jar and foo-1.0.1.jar in current directory, you may run this bash script:
# 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
Sure, that's not fully automated method, you still should to check diff output manually. Still, that's better, than nothing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With