SlideShare a Scribd company logo
Java Library Evolution Puzzlers 
Jens Dietrich1 
1Massey University 
School of Engineering and Advanced Technology 
Palmerston North, New Zealand 
https://sites.google.com/site/jensdietrich/ 
Email: j.b.dietrich /at/ massey.ac.nz 
August 31, 2014 
1
Revision History 
Revision Date Remarks 
1.0 13 Sept 13 initial version 
2.0 10 Feb 14 added bridge (synthetic methods 
generated by compiler) 
3.0 14 Feb 14 added generics3 (changing the order 
of multiple type parameter bounds) 
4.0 31 Aug 14 added static* (static vs non-static) 
2
Table of Contents 
Introduction 
Modifying Interfaces 
Modifying Method Signatures 
Static vs Non-Static 
Primitive vs Wrapper Types 
Using Generic Parameter Types 
Changing the Values of Constants 
Modifying Exceptions 
3
Introduction - Deploying Java Programs 
I Java programs are usually built (ant,maven,gradle,..) with all 
libraries they use, and then deployed 
I if the program or a library changes, the program is rebuilt and 
redeployed 
I the build step includes V&V: compiling and (automated 
regression) testing 
I partial library upgrades are becoming more and more popular, 
example: OSGi bundle updates 
I the puzzlers described here show the dierence between these 
two deployment modes 
4
Introduction - Source vs Binary Compatibility 
I a program is source compatible with a library lib.jar if the 
program uses the library, and compilation succeeds: 
javac -cp ..,lib.jar,.. ... 
I source compatibility is checked by the compiler, 
incompatibility results in compilation errors 
I a program is binary compatible with a library lib.jar if it 
links and runs with this library: 
java -cp ..,lib.jar,.. .. [JLS, ch. 13] 
I binary compatibility is checked by the JVM, incompatibility 
results in (linkage) errors 
5
The Limitations of Binary Compatibility 
I in the JLS, a very narrow de
nition of binary (in)compatibility 
is used:  A change to a type is binary compatible with 
pre-existing binaries if pre-existing binaries that previously 
linked without error will continue to link without error. 
[JLS, ch. 13.2] 
I binary compatibility is de
ned w.r.t. to what the linker can 
detect by means of static analysis, failure results in errors 
(not exceptions) 
6
Introduction - Evolution Problems 
I assume that a program references code de
ned in 
lib-1.0.jar 
I assume that the program can be compiled successfully and 
can be executed with lib-1.0.jar without causing an error 
or exception 
I then the library evolves to lib-2.0.jar 
7
Introduction - Evolution Problems 
Questions: 
1. does the program link with lib-2.0.jar - i.e., is it binary 
compatible with lib-2.0.jar? 
2. does replacing the library change the behaviour of the program 
- i.e., is the library change binary behavioural compatible? 
3. does the program compile against lib-2.0.jar - i.e., is it 
source compatible with lib-2.0.jar? 
4. does recompiling the program against the changed library 
change the behaviour of the program - i.e., is the library 
change source behavioural compatible? 
8
Introduction - Running Experiments 
I check out code: 
hg clone https://bitbucket.org/jensdietrich/ 
java-library-evolution-puzzlers 
I each example has a program with a main class 
aPackage.Main, and two versions of classes de
ned in a 
separate library 
I cd to folder and run ant as follows: 
ant -Dpackage=aPackage 
I this will do the following: 
1. compile the two versions of the library and build lib-1.0.jar 
and lib-2.0.jar 
2. compile and run the program with lib-1.0.jar 
3. compile the program with lib-1.0.jar , but run it with 
lib-2.0.jar 
4. re-compile and run the program with lib-2.0.jar 
9
Adding a Method to an Interface 
lib-1.0.jar 
package lib.addtointerface; 
public interface Foo f 
public void foo(); 
g 
+ 
lib-2.0.jar 
package lib.addtointerface; 
public interface Foo f 
public void foo(); 
public void bar(); 
g 
program 
package addtointerface; 
import lib.addtointerface.; 
public class Main implements Foo f 
@Override public void foo() f 
System.out.println(foo); 
g 
public static void main(String[] args) f 
new Main().foo(); 
g 
g 
I the interface Foo is extended 
by adding bar() 
I but the client class 
implements the old interface 
I is this still binary compatible 
with lib-2.0.jar? 
10
Adding a Method to an Interface 
Solution 
I running the program with library version 2.0 succeeds - the 
client program is not using the method added to the interface! 
I i.e., the program (compiled with lib-1.0.jar) is binary 
compatible with lib-2.0.jar 
I but recompilation fails as Main does not implement bar() 
I i.e., the program is source incompatible with lib-2.0.jar 
11
Removing a Method from an Interface 1 
lib-1.0.jar 
package lib.removefrominterface1; 
public interface Foo f 
public void foo(); 
public void bar(); 
g 
+ 
lib-2.0.jar 
package lib.removefrominterface1; 
public interface Foo f 
public void foo(); 
g 
program 
package removefrominterface1; 
import lib.removefrominterface1.; 
public class Main implements Foo f 
@Override public void foo() f 
System.out.println(foo); 
g 
@Override public void bar() f 
System.out.println(bar); 
g 
public static void main(String[] args) f 
new Main().foo(); 
new Main().bar(); 
g 
g 
I the method bar() is removed 
from the interface Foo 
I but the client class 
implements the old interface 
12
Removing a Method from an Interface 1 
Solution 
I running the program with library version 2.0 succeeds ! 
I i.e., the program (compiled with lib-1.0.jar) is binary 
compatible with lib-2.0.jar 
I but recompilation fails as Main.bar() does not override a 
method! 
I i.e., the program is source incompatible with lib-2.0.jar 
13
Removing a Method from an Interface 2 
lib-1.0.jar 
package lib.removefrominterface2; 
public interface Foo f 
public void foo(); 
public void bar(); 
g 
+ 
lib-2.0.jar 
package lib.removefrominterface2; 
public interface Foo f 
public void foo(); 
g 
program 
package removefrominterface2; 
import lib.removefrominterface2.; 
public class Main implements Foo f 
public void foo() f 
System.out.println(foo); 
g 
public void bar() f 
System.out.println(bar); 
g 
public static void main(String[] args) f 
new Main().foo(); 
new Main().bar(); 
g 
g 
I this is almost identical to the 
previous example 
I but this time the @Override 
annotation is not used 
14
Removing a Method from an Interface 2 
Solution 
I as before, the program (compiled with lib-1.0.jar) is 
binary compatible with lib-2.0.jar 
I but recompilation also succeeds as the compiler does not 
check whether Main.bar() overrides a method 
I i.e., the program is also source compatible with 
lib-2.0.jar 
15
Removing a Method from an Interface 3 
lib-1.0.jar 
package lib.removefrominterface3; 
public interface Foo f 
public void foo(); 
public void bar(); 
g 
+ 
lib-2.0.jar 
package lib.removefrominterface3; 
public interface Foo f 
public void foo(); 
g 
program 
package removefrominterface3; 
import lib.removefrominterface3.; 
public class Main implements Foo f 
public void foo() f 
System.out.println(foo); 
g 
public void bar() f 
System.out.println(bar); 
g 
public static void main(String[] args) f 
Foo f = new Main(); 
f.foo(); 
f.bar(); 
g 
g 
I this is similar to the previous 
example 
I note the declaration of f in 
main 
16
Removing a Method from an Interface 3 
Solution 
I this time the program is binary incompatible with 
lib-2.0.jar: a linkage error (NoSuchMethodError) occurs 
as the linker now tries to
nd bar() in Foo (the declared type 
of f), not in Main (the actual type) 
I compilation against lib-2.0.jar fails for the same reason - 
the compiler also fails to
nd bar() in Foo 
I i.e., the program is source incompatible with lib-2.0.jar 
as well 
17
Specialising Return Types 1 
lib-1.0.jar 
package lib.specialiseReturnType1; 
public class Foo f 
public static java.util.Collection getColl() f 
return new java.util.ArrayList(); 
g 
g 
+ 
lib-2.0.jar 
package lib.specialiseReturnType1; 
public class Foo f 
public static java.util.List getColl() f 
return new java.util.ArrayList(); 
g 
g 
program 
package specialiseReturnType1; 
import lib.specialiseReturnType1.Foo; 
public class Main f 
public static void main(String[] args) f 
java.util.Collection coll = Foo.getColl(); 
System.out.println(coll); 
g 
g 
I return type is replaced by a 
subtype 
I i.e., postconditions are 
strengthened (method 
guarantees more) 
I program should run with 
lib-2.0.jar ! 
18
Specialising Return Types 1 
Solution 
I running the program with library version 2.0 fails ! 
I inspecting byte code (javap -c Main.class) shows that 
main references getColl as 
getColl()Ljava/util/Collection; - and this descriptor 
has changed 
I the result is a linkage error (NoSuchMethodError) 
I recompiling (and then running) the program with 
lib-2.0.jar succeeds 
I i.e., the program (compiled with lib-1.0.jar) is binary 
incompatible but source compatible with lib-2.0.jar 
19
Specialising Return Types 2 
lib-1.0.jar 
package lib.specialiseReturnType2; 
public class Foo f 
public static long getAnswer() f 
return 42L; 
g 
g 
+ 
lib-2.0.jar 
package lib.specialiseReturnType2; 
public class Foo f 
public static int getAnswer() f 
return 42; 
g 
g 
program 
package specialiseReturnType2; 
import lib.specialiseReturnType2.Foo; 
public class Main f 
public static void main(String[] args) f 
long i = Foo.getAnswer(); 
System.out.println(i); 
g 
g 
I return type is narrowed from 
long to int 
I similar to specialising 
reference types 
20
Specialising Return Types 2 
Solution 
I again, this is binary incompatible, but source compatible 
I i.e., the problem can easily be
xed through recompilation 
I clients can safely widen the int to a long 
21
Specialising Return Types 3 
lib-1.0.jar 
package lib.specialiseReturnType3; 
import java.util.; 
public class Foo f 
public Collection getColl() f 
return new ArrayList(); 
g 
g 
+ 
lib-2.0.jar 
package lib.specialiseReturnType3; 
import java.util.; 
public class Foo f 
public List getColl() f 
return new ArrayList(); 
g 
g 
program 
package specialiseReturnType3; 
import lib.specialiseReturnType3.Foo; 
import java.util.; 
public class Main extends Foo f 
public static void main(String[] args) f 
Foo f = new Main(); 
Collection c = f.getColl(); 
System.out.println(c); 
g 
@Override public Collection getColl() f 
return new HashSet(); 
g 
g 
I return type Collection is 
replaced by subtype List 
I but getColl() is now 
overridden in Main ! 
22
Specialising Return Types 3 
Solution 
I as before, the program is binary incompatible with 
lib-2.0.jar: java.lang.NoSuchMethodError: 
lib.specialiseReturnType3.Foo.getColl() 
Ljava/util/Collection 
I recompilation with lib-2.0.jar fails as well: compiler 
error: return type Collection is not compatible with List 
I i.e., the program is neither binary nor source compatible 
with lib-2.0.jar 
I when overriding a method, the return type can only be 
specialised (co-variant return types [JLS, 8.4.5]), but this does 
not apply here as the overridden method itself has specialised 
its return type 
23
Specialising Return Types 4 
lib-1.0.jar 
package lib.specialiseReturnType4; 
import java.util.; 
public class Foo f 
public Collection getColl() f 
return new ArrayList(); 
g 
g 
+ 
lib-2.0.jar 
package lib.specialiseReturnType4; 
import java.util.; 
public class Foo f 
public List getColl() f 
return new ArrayList(); 
g 
g 
program 
package specialiseReturnType4; 
import lib.specialiseReturnType4.Foo; 
import java.util.; 
public class Main extends Foo f 
public static void main(String[] args) f 
Main f = new Main(); 
Collection c = f.getColl(); 
System.out.println(c); 
g 
@Override public Collection getColl() f 
return new HashSet(); 
g 
g 
I minor change: f is now 
declared as Main, not Foo 
I what impact does this have? 
24
Specialising Return Types 4 
Solution 
I the program runs but does not compile with lib-2.0.jar ! 
I i.e., the program is binary compatible but source 
incompatible 
I to
nd out why, inspect byte code 
I Specialising Return Types 4: getColl() is referenced as 
getColl:()Ljava/util/Collection; 
- reference to local method that hasn't changed 
I Specialising Return Types 3: getColl() is referenced as 
lib/specialiseReturnType3/Foo.getColl:() 
Ljava/util/Collection; 
- reference to inherited method that has changed 
25
Generalising Parameter Types 1 
lib-1.0.jar 
package lib.generaliseParamType1; 
public class Foo f 
public static void doIt(java.util.List coll) f 
System.out.println(coll); 
g 
g 
+ 
lib-2.0.jar 
package lib.generaliseParamType1; 
public class Foo f 
public static void doIt(java.util.Collection coll) f 
System.out.println(coll); 
g 
g 
program 
package generaliseParamType1; 
import lib.generaliseParamType1.Foo; 
public class Main f 
public static void main(String[] args) f 
Foo.doIt(new java.util.ArrayList()); 
g 
g 
I param type List is replaced 
by supertype Collection 
I this can be seen as weakened 
precondition (expects less) 
I should be compatible ! 
26
Generalising Parameter Types 1 
Solution 
I running the program with library version 2.0 fails ! 
I similar to changing return types, the descriptor changes, 
resulting in a linkage error (NoSuchMethodError) 
I recompiling (and then running) the program with library 
version 2.0 succeeds 
I i.e., the program (compiled with lib-1.0.jar) is binary 
incompatible but source compatible with lib-2.0.jar 
27
Generalising Parameter Types 2 
Interface1 Interface2 
implements 
Class1 Class2 
28
Generalising Parameter Types 2 
lib-1.0.jar 
package lib.generaliseParamType2; 
public class Foo f 
public static void doIt(Class1 c) f 
System.out.println(C1); 
g 
public static void doIt(Interface2 c) f 
System.out.println(I2); 
g 
g 
+ 
lib-2.0.jar 
package lib.generaliseParamType2; 
public class Foo f 
public static void doIt(Interface1 c) f 
System.out.println(I1); 
g 
public static void doIt(Interface2 c) f 
System.out.println(I2); 
g 
g 
program 
package generaliseParamType2; 
import lib.generaliseParamType2.; 
public class Main f 
public static void main(String[] args) f 
Foo.doIt(new Class1()); 
g 
g 
I doIt is overloaded 
I can the compiler select a 
method after generalising the 
parameter type? 
29
Generalising Parameter Types 2 
Solution 
I running the program with library version 2.0 fails ! 
I the descriptor changes, resulting in a linkage error 
(NoSuchMethodError) 
I recompiling fails as well - the compiler cannot select the most 
speci
c method [JLS, 15.12]: Error: reference to doIt is 
ambiguous, both method doIt(Interface1) in Foo and method 
doIt(Interface2) in Foo match. 
I i.e., the program (compiled with lib-1.0.jar) is neither binary 
nor source compatible with lib-2.0.jar 
30
Generalising Parameter Types 3 
lib-1.0.jar 
package lib.generaliseParamType3; 
public class Foo f 
public static boolean isEven(int i) f 
return i%2==0; 
g 
g 
+ 
lib-2.0.jar 
package lib.generaliseParamType3; 
public class Foo f 
public static boolean isEven(
oat i) f 
return i%2==0; 
g 
g 
program 
package generaliseParamType3; 
import lib.generaliseParamType3.Foo; 
public class Main f 
public static void main(String[] args) f 
int n = Integer.MAX VALUE; 
System.out.println(Foo.isEven(n)); 
g 
g 
I is the program binary and 
source compatible? 
I what is printed on the 
console? 
31
Generalising Parameter Types 3 
Solution 
I the program is not binary compatible with lib-2.0.jar, 
but seems to be source compatible - it can be recompiled 
and then executed 
I however, the output changes: while the original program 
prints true, the recompiled program prints false 
I the type parameter change changes the semantics of the 
program - although the method body is not changed ! 
I the change is source compatible, but source behavioural 
incompatible 
I the problem is that the widening conversion from int to 
float results in loss of precision [JLS, ch. 5.1.2] 
32
Change a Method from Static to Non-Static 
lib-1.0.jar 
package lib.static1; 
public class Foo f 
public static void foo() f 
System.out.println(foo); 
g 
g 
+ 
lib-2.0.jar 
package lib.static1; 
public class Foo f 
public void foo() f 
System.out.println(foo); 
g 
g 
program 
package static1; 
import lib.static1.Foo; 
public class Main f 
public static void main(String[] args) f 
Foo.foo(); 
g 
g 
I remove the static modi
er 
from foo() 
33
Change a Method from Static to Non-Static 
Solution 
I the change is source incompatible: a non-static method 
cannot be referenced from a static context 
I an instance must be created to invoke a non-static method 
I but what about binary compatibility ? 
I lets consider the reverse scenario
rst 
34
Change a Method from Non-Static to Static 
lib-1.0.jar 
package lib.static2; 
public class Foo f 
public void foo() f 
System.out.println(foo); 
g 
g 
+ 
lib-2.0.jar 
package lib.static2; 
public class Foo f 
public static void foo() f 
System.out.println(foo); 
g 
g 
program 
package static2; 
import lib.static2.Foo; 
public class Main f 
public static void main(String[] args) f 
new Foo().foo(); 
g 
g 
I add a static modi
er to foo() 
35
Change a Method from Static to Non-Static 
Solution 
I the change is source compatible 
I many IDEs will generate a warning: static methods should be 
references using static context (Foo.foo()) 
I but the change is still binary incompatible: a 
java.lang.IncompatibleClassChangeError is thrown 
I the same happens in the previous scenario 
36
Static vs Non-Static 
Solution 
I the reason is the use of dierent byte code instructions: 
I static methods are invoked using invokestatic, for 
non-static methods, invokevirtual is used instead 
I the JVM checks the method type during linking, and creates 
an IncompatibleClassChangeError if a unexpected type is 
encountered [JVMS, ch. 5.4] 
I the same applies for
eld (read and write) access: there are 
dierent byte code instructions for accessing static and 
non-static
elds: getfield, putfield, getstatic, 
putstatic 
37
Primitive vs Wrapper Types 1 
lib-1.0.jar 
package lib.primwrap1; 
public class Foo f 
public static int MAGIC = 42; 
g 
+ 
lib-2.0.jar 
package lib.primwrap1; 
public class Foo f 
public static Integer MAGIC = new Integer(42); 
g 
program 
package primwrap1; 
import lib.primwrap1.Foo; 
public class Main f 
public static void main(String[] args) f 
int i = Foo.MAGIC; 
System.out.println(i); 
g 
g 
I the
eld type int is replaced 
by its wrapper type Integer 
I is this transparent to the 
client program? 
38
Primitive vs Wrapper Types 1 
Solution 
I running the program with library version 2.0 fails ! 
I the descriptors have types, resulting in a linkage error 
(NoSuchFieldError) 
I recompiling (and then running) the program with 
lib-2.0.jar succeeds - the compiler applies unboxing 
[JLS, 5.1.8] 
I i.e., the program is binary incompatible but source 
compatible with lib-2.0.jar 
39
Primitive vs Wrapper Types 2 
lib-1.0.jar 
package lib.primwrap2; 
public class Foo f 
public static Integer MAGIC = new Integer(42); 
g 
+ 
lib-2.0.jar 
package lib.primwrap2; 
public class Foo f 
public static int MAGIC = 42; 
g 
program 
package primwrap2; 
import lib.primwrap2.Foo; 
public class Main f 
public static void main(String[] args) f 
Integer i = Foo.MAGIC; 
System.out.println(i); 
g 
g 
I the
eld type Integer is 
replaced by the respective 
primitive type int 
I is this transparent to the 
client program? 
40
Primitive vs Wrapper Types 2 
Solution 
I running the program with library version 2.0 fails ! 
I the descriptors have dierent types, resulting in a linkage error 
(NoSuchFieldError) 
I recompiling (and then running) the program with 
lib-2.0.jar succeeds - the compiler applies boxing [JLS, 
5.1.7] 
I i.e., the program is binary incompatible but source 
compatible with lib-2.0.jar 
41
Generics 1 
lib-1.0.jar 
package lib.generics1; 
import java.util.; 
public class Foo f 
public static ListString getList() f 
ListString list = new ArrayListString(); 
list.add(42); 
return list; 
g 
g 
+ 
lib-2.0.jar 
package lib.generics1; 
import java.util.; 
public class Foo f 
public static ListInteger getList() f 
ListInteger list = new ArrayListInteger(); 
list.add(42); 
return list; 
g 
g 
program 
package generics1; 
import lib.generics1.; 
public class Main f 
public static void main(String[] args) f 
java.util.ListString list = Foo.getList(); 
System.out.println(list.size()); 
g 
g 
I generic type parameter in 
method return type is 
changed 
I does this matter? 
42
Generics 1 
Solution 
I this is binary compatible due to type erasure in Java 
I however, this is not source compatible - the compiler cannot 
assign a list of integers to a variable declared as a list of 
strings 
43
Generics 2 
lib-1.0.jar 
package lib.generics2; 
import java.util.; 
public class Foo f 
public static ListString getList() f 
ListString list = new ArrayListString(); 
list.add(42); 
return list; 
g 
g 
+ 
lib-2.0.jar 
package lib.generics2; 
import java.util.; 
public class Foo f 
public static ListInteger getList() f 
ListInteger list = new ArrayListInteger(); 
list.add(42); 
return list; 
g 
g 
program 
package generics2; 
import lib.generics2.; 
public class Main f 
public static void main(String[] args) f 
java.util.ListString list = Foo.getList(); 
for (String s:list) f 
System.out.println(s); 
g 
g 
g 
I note that only the way the 
generic type is used has 
changed 
I the program iterates over the 
strings in the list 
44
Generics 2 
Solution 
I this is binary compatible acc. to the JLS 
I when the elements are accessed inside the loop, a cast 
instruction (checkcast) is inserted by the compiler 
I this cast fails when the list is changed to a list of integers, and 
a runtime exception is thrown 
I the change is therefore binary behavioural incompatible 
I this is not source compatible either 
45
Generics 3 
lib-1.0.jar 
package lib.generics3; 
import java.io.Serializable; 
public class FooT extends Serializable  Comparable f 
public void foo(T t) f 
t.compareTo(); 
System.out.println(t); 
g 
g 
+ 
lib-2.0.jar 
package lib.generics3; 
import java.io.Serializable; 
public class FooT extends Comparable  Serializablef 
public void foo(T t) f 
t.compareTo(); 
System.out.println(t); 
g 
g 
program 
package generics3; 
import lib.generics3.; 
public class Main implements java.io.Serializable f 
public static void main(String[] args) f 
Main m = new Main(); 
new Foo().foo(m); 
g 
g 
I Main only implements 
Serializable, but not 
Comparable 
I can Main even be compiled ? 
I what is the impact of 
changing the order of the 
interfaces de
ning the bounds 
of the type parameter? 
46
Generics 3 
Solution 
I the program compiles and links with lib-1.0.jar, despite 
not implementing both interfaces! 
I however, executing the program with lib-1.0.jar leads to a 
ClassCastException 
I the reason for this is how erasure works: only the leftmost 
bound is used [JLS, ch. 4.6] 
I i.e., foo(T) is referenced as foo(Serializable) 
I before compareTo is invoked (at runtime!), the parameter is 
cast to Comparable, and this fails 
47
Generics 3 
Solution ctd 
I changing the order of the interfaces in lib-2.0.jar is binary 
and source incompatible 
I now the leftmost bound is Comparable, i.e., foo(T) is 
referenced as foo(Comparable) 
I this incompatibility is detected by both the compiler and the 
linker 
48
Constants 1 
lib-1.0.jar 
package lib.constants1; 
public class Foo f 
public static
nal int MAGIC = 42; 
g 
+ 
lib-2.0.jar 
package lib.constants1; 
public class Foo f 
public static
nal int MAGIC = 43; 
g 
program 
package constants1; 
import lib.constants1.; 
public class Main f 
public static void main(String[] args) f 
System.out.println(Foo.MAGIC); 
g 
g 
I now the question is: what 
does this program print? 
49
Constants 1 
Solution 
I the program prints 42 when it is executed with lib-1.0.jar 
as expected 
I but the program still prints 42 when executed with 
lib-2.0.jar ! 
I the compiler inlines the constant value into the client class 
I this is binary compatibility but binary behavioural 
incompatible 
50
Constants 2 
lib-1.0.jar 
package lib.constants2; 
public class Foo f 
public static
nal String MAGIC = 42; 
g 
+ 
lib-2.0.jar 
package lib.constants2; 
public class Foo f 
public static
nal String MAGIC = 43; 
g 
program 
package constants2; 
import lib.constants2.; 
public class Main f 
public static void main(String[] args) f 
System.out.println(Foo.MAGIC); 
g 
g 
I inlining is applied to 
primitive data types, but 
what about strings? 
I what will be printed to the 
console? 
51
Constants 2 
Solution 
I the program still prints 42 when it is executed with 
lib-2.0.jar 
I constant inlining is still applied when strings are used 
I strings are immutable objects, and in many cases can be 
treated like primitive types 
I this is binary compatibility but binary behavioural 
incompatible 
52
Constants 3 
lib-1.0.jar 
package lib.constants3; 
public class Foo f 
public static
nal int MAGIC = 40+2; 
g 
+ 
lib-2.0.jar 
package lib.constants3; 
public class Foo f 
public static
nal int MAGIC = 40+3; 
g 
program 
package constants3; 
import lib.constants3.; 
public class Main f 
public static void main(String[] args) f 
System.out.println(Foo.MAGIC); 
g 
g 
I now the constant value is 
de
ned by an expression 
I what will be printed to the 
console? 
53
Constants 3 
Solution 
I the program still prints 42 when it is executed with 
lib-2.0.jar 
I the compiler applies constant folding 
I this does not seem to be speci

More Related Content

Similar to Java Library Evolution Puzzlers

SFScon19 - Paolo Boldi - Software Ecosystems as Networks the FASTEN project
SFScon19 - Paolo Boldi - Software Ecosystems as Networks the FASTEN projectSFScon19 - Paolo Boldi - Software Ecosystems as Networks the FASTEN project
SFScon19 - Paolo Boldi - Software Ecosystems as Networks the FASTEN projectSouth Tyrol Free Software Conference
 
Presentation of the FASTEN project, Conference SFScon, Bolzano, Italy
Presentation of the FASTEN project, Conference SFScon, Bolzano, Italy Presentation of the FASTEN project, Conference SFScon, Bolzano, Italy
Presentation of the FASTEN project, Conference SFScon, Bolzano, Italy Fasten Project
 
SFScon 2020 - Paolo Boldi - Software Ecosystems as Networks Advances on the F...
SFScon 2020 - Paolo Boldi - Software Ecosystems as Networks Advances on the F...SFScon 2020 - Paolo Boldi - Software Ecosystems as Networks Advances on the F...
SFScon 2020 - Paolo Boldi - Software Ecosystems as Networks Advances on the F...South Tyrol Free Software Conference
 
Native hook mechanism in Android Bionic linker
Native hook mechanism in Android Bionic linkerNative hook mechanism in Android Bionic linker
Native hook mechanism in Android Bionic linkerKevin Mai-Hsuan Chia
 
Golang execution modes
Golang execution modesGolang execution modes
Golang execution modesTing-Li Chou
 
4 Task 2- Understanding the Vulnerable Program The vulnerable program.pdf
4 Task 2- Understanding the Vulnerable Program The vulnerable program.pdf4 Task 2- Understanding the Vulnerable Program The vulnerable program.pdf
4 Task 2- Understanding the Vulnerable Program The vulnerable program.pdfatozshoppe
 
Create a PHP Library the right way
Create a PHP Library the right wayCreate a PHP Library the right way
Create a PHP Library the right wayChristian Varela
 
Managing Change
Managing ChangeManaging Change
Managing ChangeMirko Jahn
 
Convert your package to multibuild on Open Build Service
Convert your package to multibuild on Open Build ServiceConvert your package to multibuild on Open Build Service
Convert your package to multibuild on Open Build ServiceSUSE Labs Taipei
 
Advanced c programming in Linux
Advanced c programming in Linux Advanced c programming in Linux
Advanced c programming in Linux Mohammad Golyani
 
What's New In Python 2.5
What's New In Python 2.5What's New In Python 2.5
What's New In Python 2.5Richard Jones
 
Android Internal Library Management
Android Internal Library ManagementAndroid Internal Library Management
Android Internal Library ManagementKelly Shuster
 
EXTERN -- wherever u define variables, it will get access to use them
EXTERN -- wherever u define variables, it will get access to use themEXTERN -- wherever u define variables, it will get access to use them
EXTERN -- wherever u define variables, it will get access to use themAjay Chimmani
 
C, C++ Interview Questions Part - 1
C, C++ Interview Questions Part - 1C, C++ Interview Questions Part - 1
C, C++ Interview Questions Part - 1ReKruiTIn.com
 
An Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersAn Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersKostas Saidis
 
3DC Intro to Git Workshop
3DC Intro to Git Workshop3DC Intro to Git Workshop
3DC Intro to Git WorkshopBeckhamWee
 

Similar to Java Library Evolution Puzzlers (20)

SFScon19 - Paolo Boldi - Software Ecosystems as Networks the FASTEN project
SFScon19 - Paolo Boldi - Software Ecosystems as Networks the FASTEN projectSFScon19 - Paolo Boldi - Software Ecosystems as Networks the FASTEN project
SFScon19 - Paolo Boldi - Software Ecosystems as Networks the FASTEN project
 
Presentation of the FASTEN project, Conference SFScon, Bolzano, Italy
Presentation of the FASTEN project, Conference SFScon, Bolzano, Italy Presentation of the FASTEN project, Conference SFScon, Bolzano, Italy
Presentation of the FASTEN project, Conference SFScon, Bolzano, Italy
 
SFScon 2020 - Paolo Boldi - Software Ecosystems as Networks Advances on the F...
SFScon 2020 - Paolo Boldi - Software Ecosystems as Networks Advances on the F...SFScon 2020 - Paolo Boldi - Software Ecosystems as Networks Advances on the F...
SFScon 2020 - Paolo Boldi - Software Ecosystems as Networks Advances on the F...
 
Native hook mechanism in Android Bionic linker
Native hook mechanism in Android Bionic linkerNative hook mechanism in Android Bionic linker
Native hook mechanism in Android Bionic linker
 
Golang execution modes
Golang execution modesGolang execution modes
Golang execution modes
 
4 Task 2- Understanding the Vulnerable Program The vulnerable program.pdf
4 Task 2- Understanding the Vulnerable Program The vulnerable program.pdf4 Task 2- Understanding the Vulnerable Program The vulnerable program.pdf
4 Task 2- Understanding the Vulnerable Program The vulnerable program.pdf
 
Create a PHP Library the right way
Create a PHP Library the right wayCreate a PHP Library the right way
Create a PHP Library the right way
 
Managing Change
Managing ChangeManaging Change
Managing Change
 
Convert your package to multibuild on Open Build Service
Convert your package to multibuild on Open Build ServiceConvert your package to multibuild on Open Build Service
Convert your package to multibuild on Open Build Service
 
What's New in Groovy 1.6?
What's New in Groovy 1.6?What's New in Groovy 1.6?
What's New in Groovy 1.6?
 
Composer namespacing
Composer namespacingComposer namespacing
Composer namespacing
 
Advanced c programming in Linux
Advanced c programming in Linux Advanced c programming in Linux
Advanced c programming in Linux
 
What's New In Python 2.5
What's New In Python 2.5What's New In Python 2.5
What's New In Python 2.5
 
Android Internal Library Management
Android Internal Library ManagementAndroid Internal Library Management
Android Internal Library Management
 
EXTERN -- wherever u define variables, it will get access to use them
EXTERN -- wherever u define variables, it will get access to use themEXTERN -- wherever u define variables, it will get access to use them
EXTERN -- wherever u define variables, it will get access to use them
 
A05
A05A05
A05
 
Scope of Variables.pptx
Scope of Variables.pptxScope of Variables.pptx
Scope of Variables.pptx
 
C, C++ Interview Questions Part - 1
C, C++ Interview Questions Part - 1C, C++ Interview Questions Part - 1
C, C++ Interview Questions Part - 1
 
An Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersAn Introduction to Gradle for Java Developers
An Introduction to Gradle for Java Developers
 
3DC Intro to Git Workshop
3DC Intro to Git Workshop3DC Intro to Git Workshop
3DC Intro to Git Workshop
 

Recently uploaded

How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...Product School
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backElena Simperl
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingThijs Feryn
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3DianaGray10
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaRTTS
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Tobias Schneck
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGuy Korland
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfCheryl Hung
 
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™UiPathCommunity
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor TurskyiFwdays
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...Product School
 
КАТЕРИНА АБЗЯТОВА «Ефективне планування тестування ключові аспекти та практ...
КАТЕРИНА АБЗЯТОВА  «Ефективне планування тестування  ключові аспекти та практ...КАТЕРИНА АБЗЯТОВА  «Ефективне планування тестування  ключові аспекти та практ...
КАТЕРИНА АБЗЯТОВА «Ефективне планування тестування ключові аспекти та практ...QADay
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf91mobiles
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsDorra BARTAGUIZ
 
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlPeter Udo Diehl
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonDianaGray10
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxAbida Shariff
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...Elena Simperl
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupCatarinaPereira64715
 

Recently uploaded (20)

How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
КАТЕРИНА АБЗЯТОВА «Ефективне планування тестування ключові аспекти та практ...
КАТЕРИНА АБЗЯТОВА  «Ефективне планування тестування  ключові аспекти та практ...КАТЕРИНА АБЗЯТОВА  «Ефективне планування тестування  ключові аспекти та практ...
КАТЕРИНА АБЗЯТОВА «Ефективне планування тестування ключові аспекти та практ...
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
 

Java Library Evolution Puzzlers

  • 1. Java Library Evolution Puzzlers Jens Dietrich1 1Massey University School of Engineering and Advanced Technology Palmerston North, New Zealand https://sites.google.com/site/jensdietrich/ Email: j.b.dietrich /at/ massey.ac.nz August 31, 2014 1
  • 2. Revision History Revision Date Remarks 1.0 13 Sept 13 initial version 2.0 10 Feb 14 added bridge (synthetic methods generated by compiler) 3.0 14 Feb 14 added generics3 (changing the order of multiple type parameter bounds) 4.0 31 Aug 14 added static* (static vs non-static) 2
  • 3. Table of Contents Introduction Modifying Interfaces Modifying Method Signatures Static vs Non-Static Primitive vs Wrapper Types Using Generic Parameter Types Changing the Values of Constants Modifying Exceptions 3
  • 4. Introduction - Deploying Java Programs I Java programs are usually built (ant,maven,gradle,..) with all libraries they use, and then deployed I if the program or a library changes, the program is rebuilt and redeployed I the build step includes V&V: compiling and (automated regression) testing I partial library upgrades are becoming more and more popular, example: OSGi bundle updates I the puzzlers described here show the dierence between these two deployment modes 4
  • 5. Introduction - Source vs Binary Compatibility I a program is source compatible with a library lib.jar if the program uses the library, and compilation succeeds: javac -cp ..,lib.jar,.. ... I source compatibility is checked by the compiler, incompatibility results in compilation errors I a program is binary compatible with a library lib.jar if it links and runs with this library: java -cp ..,lib.jar,.. .. [JLS, ch. 13] I binary compatibility is checked by the JVM, incompatibility results in (linkage) errors 5
  • 6. The Limitations of Binary Compatibility I in the JLS, a very narrow de
  • 7. nition of binary (in)compatibility is used: A change to a type is binary compatible with pre-existing binaries if pre-existing binaries that previously linked without error will continue to link without error. [JLS, ch. 13.2] I binary compatibility is de
  • 8. ned w.r.t. to what the linker can detect by means of static analysis, failure results in errors (not exceptions) 6
  • 9. Introduction - Evolution Problems I assume that a program references code de
  • 10. ned in lib-1.0.jar I assume that the program can be compiled successfully and can be executed with lib-1.0.jar without causing an error or exception I then the library evolves to lib-2.0.jar 7
  • 11. Introduction - Evolution Problems Questions: 1. does the program link with lib-2.0.jar - i.e., is it binary compatible with lib-2.0.jar? 2. does replacing the library change the behaviour of the program - i.e., is the library change binary behavioural compatible? 3. does the program compile against lib-2.0.jar - i.e., is it source compatible with lib-2.0.jar? 4. does recompiling the program against the changed library change the behaviour of the program - i.e., is the library change source behavioural compatible? 8
  • 12. Introduction - Running Experiments I check out code: hg clone https://bitbucket.org/jensdietrich/ java-library-evolution-puzzlers I each example has a program with a main class aPackage.Main, and two versions of classes de
  • 13. ned in a separate library I cd to folder and run ant as follows: ant -Dpackage=aPackage I this will do the following: 1. compile the two versions of the library and build lib-1.0.jar and lib-2.0.jar 2. compile and run the program with lib-1.0.jar 3. compile the program with lib-1.0.jar , but run it with lib-2.0.jar 4. re-compile and run the program with lib-2.0.jar 9
  • 14. Adding a Method to an Interface lib-1.0.jar package lib.addtointerface; public interface Foo f public void foo(); g + lib-2.0.jar package lib.addtointerface; public interface Foo f public void foo(); public void bar(); g program package addtointerface; import lib.addtointerface.; public class Main implements Foo f @Override public void foo() f System.out.println(foo); g public static void main(String[] args) f new Main().foo(); g g I the interface Foo is extended by adding bar() I but the client class implements the old interface I is this still binary compatible with lib-2.0.jar? 10
  • 15. Adding a Method to an Interface Solution I running the program with library version 2.0 succeeds - the client program is not using the method added to the interface! I i.e., the program (compiled with lib-1.0.jar) is binary compatible with lib-2.0.jar I but recompilation fails as Main does not implement bar() I i.e., the program is source incompatible with lib-2.0.jar 11
  • 16. Removing a Method from an Interface 1 lib-1.0.jar package lib.removefrominterface1; public interface Foo f public void foo(); public void bar(); g + lib-2.0.jar package lib.removefrominterface1; public interface Foo f public void foo(); g program package removefrominterface1; import lib.removefrominterface1.; public class Main implements Foo f @Override public void foo() f System.out.println(foo); g @Override public void bar() f System.out.println(bar); g public static void main(String[] args) f new Main().foo(); new Main().bar(); g g I the method bar() is removed from the interface Foo I but the client class implements the old interface 12
  • 17. Removing a Method from an Interface 1 Solution I running the program with library version 2.0 succeeds ! I i.e., the program (compiled with lib-1.0.jar) is binary compatible with lib-2.0.jar I but recompilation fails as Main.bar() does not override a method! I i.e., the program is source incompatible with lib-2.0.jar 13
  • 18. Removing a Method from an Interface 2 lib-1.0.jar package lib.removefrominterface2; public interface Foo f public void foo(); public void bar(); g + lib-2.0.jar package lib.removefrominterface2; public interface Foo f public void foo(); g program package removefrominterface2; import lib.removefrominterface2.; public class Main implements Foo f public void foo() f System.out.println(foo); g public void bar() f System.out.println(bar); g public static void main(String[] args) f new Main().foo(); new Main().bar(); g g I this is almost identical to the previous example I but this time the @Override annotation is not used 14
  • 19. Removing a Method from an Interface 2 Solution I as before, the program (compiled with lib-1.0.jar) is binary compatible with lib-2.0.jar I but recompilation also succeeds as the compiler does not check whether Main.bar() overrides a method I i.e., the program is also source compatible with lib-2.0.jar 15
  • 20. Removing a Method from an Interface 3 lib-1.0.jar package lib.removefrominterface3; public interface Foo f public void foo(); public void bar(); g + lib-2.0.jar package lib.removefrominterface3; public interface Foo f public void foo(); g program package removefrominterface3; import lib.removefrominterface3.; public class Main implements Foo f public void foo() f System.out.println(foo); g public void bar() f System.out.println(bar); g public static void main(String[] args) f Foo f = new Main(); f.foo(); f.bar(); g g I this is similar to the previous example I note the declaration of f in main 16
  • 21. Removing a Method from an Interface 3 Solution I this time the program is binary incompatible with lib-2.0.jar: a linkage error (NoSuchMethodError) occurs as the linker now tries to
  • 22. nd bar() in Foo (the declared type of f), not in Main (the actual type) I compilation against lib-2.0.jar fails for the same reason - the compiler also fails to
  • 23. nd bar() in Foo I i.e., the program is source incompatible with lib-2.0.jar as well 17
  • 24. Specialising Return Types 1 lib-1.0.jar package lib.specialiseReturnType1; public class Foo f public static java.util.Collection getColl() f return new java.util.ArrayList(); g g + lib-2.0.jar package lib.specialiseReturnType1; public class Foo f public static java.util.List getColl() f return new java.util.ArrayList(); g g program package specialiseReturnType1; import lib.specialiseReturnType1.Foo; public class Main f public static void main(String[] args) f java.util.Collection coll = Foo.getColl(); System.out.println(coll); g g I return type is replaced by a subtype I i.e., postconditions are strengthened (method guarantees more) I program should run with lib-2.0.jar ! 18
  • 25. Specialising Return Types 1 Solution I running the program with library version 2.0 fails ! I inspecting byte code (javap -c Main.class) shows that main references getColl as getColl()Ljava/util/Collection; - and this descriptor has changed I the result is a linkage error (NoSuchMethodError) I recompiling (and then running) the program with lib-2.0.jar succeeds I i.e., the program (compiled with lib-1.0.jar) is binary incompatible but source compatible with lib-2.0.jar 19
  • 26. Specialising Return Types 2 lib-1.0.jar package lib.specialiseReturnType2; public class Foo f public static long getAnswer() f return 42L; g g + lib-2.0.jar package lib.specialiseReturnType2; public class Foo f public static int getAnswer() f return 42; g g program package specialiseReturnType2; import lib.specialiseReturnType2.Foo; public class Main f public static void main(String[] args) f long i = Foo.getAnswer(); System.out.println(i); g g I return type is narrowed from long to int I similar to specialising reference types 20
  • 27. Specialising Return Types 2 Solution I again, this is binary incompatible, but source compatible I i.e., the problem can easily be
  • 28. xed through recompilation I clients can safely widen the int to a long 21
  • 29. Specialising Return Types 3 lib-1.0.jar package lib.specialiseReturnType3; import java.util.; public class Foo f public Collection getColl() f return new ArrayList(); g g + lib-2.0.jar package lib.specialiseReturnType3; import java.util.; public class Foo f public List getColl() f return new ArrayList(); g g program package specialiseReturnType3; import lib.specialiseReturnType3.Foo; import java.util.; public class Main extends Foo f public static void main(String[] args) f Foo f = new Main(); Collection c = f.getColl(); System.out.println(c); g @Override public Collection getColl() f return new HashSet(); g g I return type Collection is replaced by subtype List I but getColl() is now overridden in Main ! 22
  • 30. Specialising Return Types 3 Solution I as before, the program is binary incompatible with lib-2.0.jar: java.lang.NoSuchMethodError: lib.specialiseReturnType3.Foo.getColl() Ljava/util/Collection I recompilation with lib-2.0.jar fails as well: compiler error: return type Collection is not compatible with List I i.e., the program is neither binary nor source compatible with lib-2.0.jar I when overriding a method, the return type can only be specialised (co-variant return types [JLS, 8.4.5]), but this does not apply here as the overridden method itself has specialised its return type 23
  • 31. Specialising Return Types 4 lib-1.0.jar package lib.specialiseReturnType4; import java.util.; public class Foo f public Collection getColl() f return new ArrayList(); g g + lib-2.0.jar package lib.specialiseReturnType4; import java.util.; public class Foo f public List getColl() f return new ArrayList(); g g program package specialiseReturnType4; import lib.specialiseReturnType4.Foo; import java.util.; public class Main extends Foo f public static void main(String[] args) f Main f = new Main(); Collection c = f.getColl(); System.out.println(c); g @Override public Collection getColl() f return new HashSet(); g g I minor change: f is now declared as Main, not Foo I what impact does this have? 24
  • 32. Specialising Return Types 4 Solution I the program runs but does not compile with lib-2.0.jar ! I i.e., the program is binary compatible but source incompatible I to
  • 33. nd out why, inspect byte code I Specialising Return Types 4: getColl() is referenced as getColl:()Ljava/util/Collection; - reference to local method that hasn't changed I Specialising Return Types 3: getColl() is referenced as lib/specialiseReturnType3/Foo.getColl:() Ljava/util/Collection; - reference to inherited method that has changed 25
  • 34. Generalising Parameter Types 1 lib-1.0.jar package lib.generaliseParamType1; public class Foo f public static void doIt(java.util.List coll) f System.out.println(coll); g g + lib-2.0.jar package lib.generaliseParamType1; public class Foo f public static void doIt(java.util.Collection coll) f System.out.println(coll); g g program package generaliseParamType1; import lib.generaliseParamType1.Foo; public class Main f public static void main(String[] args) f Foo.doIt(new java.util.ArrayList()); g g I param type List is replaced by supertype Collection I this can be seen as weakened precondition (expects less) I should be compatible ! 26
  • 35. Generalising Parameter Types 1 Solution I running the program with library version 2.0 fails ! I similar to changing return types, the descriptor changes, resulting in a linkage error (NoSuchMethodError) I recompiling (and then running) the program with library version 2.0 succeeds I i.e., the program (compiled with lib-1.0.jar) is binary incompatible but source compatible with lib-2.0.jar 27
  • 36. Generalising Parameter Types 2 Interface1 Interface2 implements Class1 Class2 28
  • 37. Generalising Parameter Types 2 lib-1.0.jar package lib.generaliseParamType2; public class Foo f public static void doIt(Class1 c) f System.out.println(C1); g public static void doIt(Interface2 c) f System.out.println(I2); g g + lib-2.0.jar package lib.generaliseParamType2; public class Foo f public static void doIt(Interface1 c) f System.out.println(I1); g public static void doIt(Interface2 c) f System.out.println(I2); g g program package generaliseParamType2; import lib.generaliseParamType2.; public class Main f public static void main(String[] args) f Foo.doIt(new Class1()); g g I doIt is overloaded I can the compiler select a method after generalising the parameter type? 29
  • 38. Generalising Parameter Types 2 Solution I running the program with library version 2.0 fails ! I the descriptor changes, resulting in a linkage error (NoSuchMethodError) I recompiling fails as well - the compiler cannot select the most speci
  • 39. c method [JLS, 15.12]: Error: reference to doIt is ambiguous, both method doIt(Interface1) in Foo and method doIt(Interface2) in Foo match. I i.e., the program (compiled with lib-1.0.jar) is neither binary nor source compatible with lib-2.0.jar 30
  • 40. Generalising Parameter Types 3 lib-1.0.jar package lib.generaliseParamType3; public class Foo f public static boolean isEven(int i) f return i%2==0; g g + lib-2.0.jar package lib.generaliseParamType3; public class Foo f public static boolean isEven( oat i) f return i%2==0; g g program package generaliseParamType3; import lib.generaliseParamType3.Foo; public class Main f public static void main(String[] args) f int n = Integer.MAX VALUE; System.out.println(Foo.isEven(n)); g g I is the program binary and source compatible? I what is printed on the console? 31
  • 41. Generalising Parameter Types 3 Solution I the program is not binary compatible with lib-2.0.jar, but seems to be source compatible - it can be recompiled and then executed I however, the output changes: while the original program prints true, the recompiled program prints false I the type parameter change changes the semantics of the program - although the method body is not changed ! I the change is source compatible, but source behavioural incompatible I the problem is that the widening conversion from int to float results in loss of precision [JLS, ch. 5.1.2] 32
  • 42. Change a Method from Static to Non-Static lib-1.0.jar package lib.static1; public class Foo f public static void foo() f System.out.println(foo); g g + lib-2.0.jar package lib.static1; public class Foo f public void foo() f System.out.println(foo); g g program package static1; import lib.static1.Foo; public class Main f public static void main(String[] args) f Foo.foo(); g g I remove the static modi
  • 44. Change a Method from Static to Non-Static Solution I the change is source incompatible: a non-static method cannot be referenced from a static context I an instance must be created to invoke a non-static method I but what about binary compatibility ? I lets consider the reverse scenario
  • 46. Change a Method from Non-Static to Static lib-1.0.jar package lib.static2; public class Foo f public void foo() f System.out.println(foo); g g + lib-2.0.jar package lib.static2; public class Foo f public static void foo() f System.out.println(foo); g g program package static2; import lib.static2.Foo; public class Main f public static void main(String[] args) f new Foo().foo(); g g I add a static modi
  • 48. Change a Method from Static to Non-Static Solution I the change is source compatible I many IDEs will generate a warning: static methods should be references using static context (Foo.foo()) I but the change is still binary incompatible: a java.lang.IncompatibleClassChangeError is thrown I the same happens in the previous scenario 36
  • 49. Static vs Non-Static Solution I the reason is the use of dierent byte code instructions: I static methods are invoked using invokestatic, for non-static methods, invokevirtual is used instead I the JVM checks the method type during linking, and creates an IncompatibleClassChangeError if a unexpected type is encountered [JVMS, ch. 5.4] I the same applies for
  • 50. eld (read and write) access: there are dierent byte code instructions for accessing static and non-static
  • 51. elds: getfield, putfield, getstatic, putstatic 37
  • 52. Primitive vs Wrapper Types 1 lib-1.0.jar package lib.primwrap1; public class Foo f public static int MAGIC = 42; g + lib-2.0.jar package lib.primwrap1; public class Foo f public static Integer MAGIC = new Integer(42); g program package primwrap1; import lib.primwrap1.Foo; public class Main f public static void main(String[] args) f int i = Foo.MAGIC; System.out.println(i); g g I the
  • 53. eld type int is replaced by its wrapper type Integer I is this transparent to the client program? 38
  • 54. Primitive vs Wrapper Types 1 Solution I running the program with library version 2.0 fails ! I the descriptors have types, resulting in a linkage error (NoSuchFieldError) I recompiling (and then running) the program with lib-2.0.jar succeeds - the compiler applies unboxing [JLS, 5.1.8] I i.e., the program is binary incompatible but source compatible with lib-2.0.jar 39
  • 55. Primitive vs Wrapper Types 2 lib-1.0.jar package lib.primwrap2; public class Foo f public static Integer MAGIC = new Integer(42); g + lib-2.0.jar package lib.primwrap2; public class Foo f public static int MAGIC = 42; g program package primwrap2; import lib.primwrap2.Foo; public class Main f public static void main(String[] args) f Integer i = Foo.MAGIC; System.out.println(i); g g I the
  • 56. eld type Integer is replaced by the respective primitive type int I is this transparent to the client program? 40
  • 57. Primitive vs Wrapper Types 2 Solution I running the program with library version 2.0 fails ! I the descriptors have dierent types, resulting in a linkage error (NoSuchFieldError) I recompiling (and then running) the program with lib-2.0.jar succeeds - the compiler applies boxing [JLS, 5.1.7] I i.e., the program is binary incompatible but source compatible with lib-2.0.jar 41
  • 58. Generics 1 lib-1.0.jar package lib.generics1; import java.util.; public class Foo f public static ListString getList() f ListString list = new ArrayListString(); list.add(42); return list; g g + lib-2.0.jar package lib.generics1; import java.util.; public class Foo f public static ListInteger getList() f ListInteger list = new ArrayListInteger(); list.add(42); return list; g g program package generics1; import lib.generics1.; public class Main f public static void main(String[] args) f java.util.ListString list = Foo.getList(); System.out.println(list.size()); g g I generic type parameter in method return type is changed I does this matter? 42
  • 59. Generics 1 Solution I this is binary compatible due to type erasure in Java I however, this is not source compatible - the compiler cannot assign a list of integers to a variable declared as a list of strings 43
  • 60. Generics 2 lib-1.0.jar package lib.generics2; import java.util.; public class Foo f public static ListString getList() f ListString list = new ArrayListString(); list.add(42); return list; g g + lib-2.0.jar package lib.generics2; import java.util.; public class Foo f public static ListInteger getList() f ListInteger list = new ArrayListInteger(); list.add(42); return list; g g program package generics2; import lib.generics2.; public class Main f public static void main(String[] args) f java.util.ListString list = Foo.getList(); for (String s:list) f System.out.println(s); g g g I note that only the way the generic type is used has changed I the program iterates over the strings in the list 44
  • 61. Generics 2 Solution I this is binary compatible acc. to the JLS I when the elements are accessed inside the loop, a cast instruction (checkcast) is inserted by the compiler I this cast fails when the list is changed to a list of integers, and a runtime exception is thrown I the change is therefore binary behavioural incompatible I this is not source compatible either 45
  • 62. Generics 3 lib-1.0.jar package lib.generics3; import java.io.Serializable; public class FooT extends Serializable Comparable f public void foo(T t) f t.compareTo(); System.out.println(t); g g + lib-2.0.jar package lib.generics3; import java.io.Serializable; public class FooT extends Comparable Serializablef public void foo(T t) f t.compareTo(); System.out.println(t); g g program package generics3; import lib.generics3.; public class Main implements java.io.Serializable f public static void main(String[] args) f Main m = new Main(); new Foo().foo(m); g g I Main only implements Serializable, but not Comparable I can Main even be compiled ? I what is the impact of changing the order of the interfaces de
  • 63. ning the bounds of the type parameter? 46
  • 64. Generics 3 Solution I the program compiles and links with lib-1.0.jar, despite not implementing both interfaces! I however, executing the program with lib-1.0.jar leads to a ClassCastException I the reason for this is how erasure works: only the leftmost bound is used [JLS, ch. 4.6] I i.e., foo(T) is referenced as foo(Serializable) I before compareTo is invoked (at runtime!), the parameter is cast to Comparable, and this fails 47
  • 65. Generics 3 Solution ctd I changing the order of the interfaces in lib-2.0.jar is binary and source incompatible I now the leftmost bound is Comparable, i.e., foo(T) is referenced as foo(Comparable) I this incompatibility is detected by both the compiler and the linker 48
  • 66. Constants 1 lib-1.0.jar package lib.constants1; public class Foo f public static
  • 67. nal int MAGIC = 42; g + lib-2.0.jar package lib.constants1; public class Foo f public static
  • 68. nal int MAGIC = 43; g program package constants1; import lib.constants1.; public class Main f public static void main(String[] args) f System.out.println(Foo.MAGIC); g g I now the question is: what does this program print? 49
  • 69. Constants 1 Solution I the program prints 42 when it is executed with lib-1.0.jar as expected I but the program still prints 42 when executed with lib-2.0.jar ! I the compiler inlines the constant value into the client class I this is binary compatibility but binary behavioural incompatible 50
  • 70. Constants 2 lib-1.0.jar package lib.constants2; public class Foo f public static
  • 71. nal String MAGIC = 42; g + lib-2.0.jar package lib.constants2; public class Foo f public static
  • 72. nal String MAGIC = 43; g program package constants2; import lib.constants2.; public class Main f public static void main(String[] args) f System.out.println(Foo.MAGIC); g g I inlining is applied to primitive data types, but what about strings? I what will be printed to the console? 51
  • 73. Constants 2 Solution I the program still prints 42 when it is executed with lib-2.0.jar I constant inlining is still applied when strings are used I strings are immutable objects, and in many cases can be treated like primitive types I this is binary compatibility but binary behavioural incompatible 52
  • 74. Constants 3 lib-1.0.jar package lib.constants3; public class Foo f public static
  • 75. nal int MAGIC = 40+2; g + lib-2.0.jar package lib.constants3; public class Foo f public static
  • 76. nal int MAGIC = 40+3; g program package constants3; import lib.constants3.; public class Main f public static void main(String[] args) f System.out.println(Foo.MAGIC); g g I now the constant value is de
  • 77. ned by an expression I what will be printed to the console? 53
  • 78. Constants 3 Solution I the program still prints 42 when it is executed with lib-2.0.jar I the compiler applies constant folding I this does not seem to be speci
  • 79. ed in [JLS] and might therefore be a compiler-speci
  • 80. c optimisation I i.e., the expression is evaluated at compile time I this is binary compatibility but binary behavioural incompatible 54
  • 81. Constants 4 lib-1.0.jar package lib.constants4; public class Foo f public static
  • 82. nal Integer MAGIC = 42; g + lib-2.0.jar package lib.constants4; public class Foo f public static
  • 83. nal Integer MAGIC = 43; g program package constants4; import lib.constants4.; public class Main f public static void main(String[] args) f System.out.println(Foo.MAGIC); g g I now the constant is de
  • 84. ned using the wrapper type I note that assignment is safe due to autoboxing I what will be printed to the console? 55
  • 85. Constants 4 Solution I now 43 is printed as expected when the program runs with lib-2.0.jar ! I i.e., simply by using wrapper types, constant inlining can be prevented (at least using the current version of the compiler) I A variable of primitive type or type String, that is
  • 86. nal and initialized with a compile-time constant expression (15.28), is called a constant variable. [JLS, ch. 4.12.4] I it is unclear why wrapper types are excluded, they are immutable as well! I this may explain why many constants in projects like velocity are de
  • 87. ned using wrapper types - to prevent inlining 56
  • 88. Exceptions I methods can declare exceptions I for checked exceptions, the compiler forces callers to handle or rethrow the exception I at runtime, when an exception occurs the JVM searches the invocation chain of the method (stack) for a suitable exception handler [JVMS, ch. 2.10] I the compiler treats exceptions as part of the method declaration - what about the JVM? I i.e., are certain changes to exceptions (removing or specialising exceptions) binary incompatible but source compatible? 57
  • 89. Adding a Runtime Exception lib-1.0.jar package lib.exceptions1; public class Foo f public static void foo() fg g + lib-2.0.jar package lib.exceptions1; public class Foo f public static void foo() throws UnsupportedOperationException f throw new UnsupportedOperationException(); g g program package exceptions1; public class Main f public static void main(String[] args) f lib.exceptions1.Foo.foo(); g g I in lib-2.0.jar , an UnsupportedOperation- Exception is declared and thrown I note that this is a runtime (unchecked) exception 58
  • 90. Adding a Runtime Exception Solution I the program is source compatible with lib-2.0.jar: UnsupportedOperationException is a runtime exception, and whether it is declared or not makes no dierence I however, while the program is binary compatible, it is binary behavioural incompatible - but this is only because the exception is actually thrown in lib-2.0.jar I if the throw statement was removed, the program would become binary behavioural compatible although the exception is still declared I it would still be possible to compile the modi
  • 91. ed program - the compiler cannot
  • 92. gure out that a declared unchecked exception is never thrown I this makes sense - runtime exceptions are thrown implicitly (null pointers, failed casts etc) and it is too dicult for the compiler to check this 59
  • 93. Adding a Checked Exception lib-1.0.jar package lib.exceptions2; public class Foo f public static void foo() f g g + lib-2.0.jar package lib.exceptions2; import java.io.IOException; public class Foo f public static void foo() throws IOException f throw new IOException(); g g program package exceptions2; public class Main f public static void main(String[] args) f lib.exceptions2.Foo.foo(); g g I in lib-2.0.jar , an IOException is declared or thrown I this is a checked exception 60
  • 94. Adding a Checked Exception Solution I not surprisingly, the change is source incompatible I however, the program is binary compatible with lib-2.0.jar I i.e., the declared exception is not detected during linking as this is not part of the method descriptor I the change is binary behavioural incompatible as the exception is thrown but not caught 61
  • 95. Generalising a Checked Exception lib-1.0.jar package lib.exceptions3; import java.io.IOException; public class Foo f public static void foo() throws IOException f throw new IOException(); g g + lib-2.0.jar package lib.exceptions3; public class Foo f public static void foo() throws Exception f throw new Exception(); g g program package exceptions3; import java.io.IOException; public class Main f public static void main(String[] args) f try f lib.exceptions3.Foo.foo(); g catch (IOException x) f System.err.println(Caught it); g g g I in lib-2.0.jar , the IOException is replaced by its super type Exception I the client program only handles the IOException 62
  • 96. Generalising a Checked Exception Solution I the program is again source incompatible but binary compatible with lib-2.0.jar I but as before, the program behaviour changes as the exception is not caught, i.e. the change is binary behavioural incompatible 63
  • 97. Specialising a Checked Exception lib-1.0.jar package lib.exceptions4; import java.io.IOException; public class Foo f public static void foo() throws Exception f throw new IOException(); g g + lib-2.0.jar package lib.exceptions4; import java.io.IOException; public class Foo f public static void foo() throws IOException f throw new IOException(); g g program package exceptions4; import java.io.IOException; public class Main f public static void main(String[] args) f try f lib.exceptions4.Foo.foo(); g catch (Exception x) f System.err.println(Caught it); g g g I in lib-2.0.jar , the Exception is replaced by its sub type IOException I this is similar to specialising the return type 64
  • 98. Specialising a Checked Exception Solution I the program is source and binary compatible with lib-2.0.jar I this is (surprisingly) dierent to specialising return types I the exceptions are not part of the method descriptor used to references method when linking 65
  • 99. Removing a Checked Exception 1 lib-1.0.jar package lib.exceptions5; import java.io.IOException; public class Foo f public static void foo() throws IOException f throw new IOException(); g g + lib-2.0.jar package lib.exceptions5; public class Foo f public static void foo() f g g program package exceptions5; import java.io.IOException; public class Main f public static void main(String[] args) f try f lib.exceptions5.Foo.foo(); g catch (IOException x) f System.err.println(Caught it); g g g I in lib-2.0.jar , the IOException is removed from the method I but note the exception handler in main 66
  • 100. Removing a Checked Exception 1 Solution I the program is binary compatible but source incompatible with lib-2.0.jar I the compiler infers that the catch statement is not reachable because the updated foo() does not throw an exception: exception IOException is never thrown in body of corresponding try statement [JLS, ch. 14.21] 67
  • 101. Removing a Checked Exception 2 lib-1.0.jar package lib.exceptions6; public class Foo f public static void foo() throws Exception f throw new Exception(); g g + lib-2.0.jar package lib.exceptions6; public class Foo f public static void foo() f g g program package exceptions6; public class Main f public static void main(String[] args) f try f lib.exceptions6.Foo.foo(); g catch (Exception x) f System.err.println(Caught it); g g g I in lib-2.0.jar , the Exception is removed from the method I but note the exception handler in main 68
  • 102. Removing a Checked Exception 2 Solution I surprisingly, the program is binary compatible and source compatible with lib-2.0.jar I the compiler still considers the catch clause as reachable I this makes sense, as Exception includes runtime exceptions 69
  • 103. Removing a Checked Exception 2 ctd Solution I however, it seems to contradict the reachability rules: A catch block C is reachable i both of the following are true: Either the type of C's parameter is an unchecked exception type or Throwable; or some expression or throw statement in the try block is reachable and can throw a checked exception whose type is assignable to the parameter of the catch clause C. [JLS, ch. 14.21] but RuntimeException and all its subclasses are, collectively, the runtime exception classes. .. The unchecked exception classes are the runtime exception classes and the error classes. [JLS, ch. 11.1.1]. I i.e., one would expect a reachability compiler error! I this has been report as a bug in the JLS, and will be
  • 104. xed in JLS-8 (email communication with Alex Buckley) 70
  • 105. Ghost lib-1.0.jar package lib.ghost; public class Foo f public static class Bar f public static void foo() f System.out.println(foo); g g g + lib-2.0.jar package lib.ghost.Foo; public class Bar f public static void foo() f System.out.println(foo); g g program package ghost; public class Main f public static void main(String[] args) f lib.ghost.Foo.Bar.foo(); g g I now the question is: what does this program print? 71
  • 106. Ghost Solution I the program is not binary compatible with lib-2.0.jar: java.lang.NoClassDefFoundError: lib/ghost/Foo$Bar I however, the program is source compatible I the problem is that the reference lib.ghost.Foo.Bar can either refer to an inner class Bar within the class lib.ghost.Foo, or a top-level class Bar in the package lib.ghost.Foo I the byte code representation however diers: lib/ghost/Foo$Bar vs lib/ghost/Foo/Bar 72
  • 107. Bridge lib-1.0.jar package lib.bridge1; public class Foo f private int foo = 0; public class Inner f @Override public String toString() f return Inner[foo=+foo+]; g g g + lib-2.0.jar package lib.bridge1; public class Foo f int foo = 0; public class Inner f @Override public String toString() f return Inner[foo=+foo+]; g g g program package bridge1; import lib.bridge1.; import java.lang.re ect.Method; public class Main f public static void main(String[] args) f Method[] mm = Foo.class.getDeclaredMethods(); for (Method m:mm) f System.out.println(m); g g g I re ection is used to
  • 108. nd out how many methods Foo has I can this be changed by only changing the access modi
  • 110. eld foo from private to default? 73
  • 111. Bridge Solution I the program is binary and source compatible with lib-2.0.jar I however, the behaviour changes I in lib-1.0.jar, a synthetic bridge method static int lib.bridge1.Foo.access$000(lib.bridge1.Foo) is generated by the compiler to enable access to the private
  • 112. eld by the inner class I this method is not necessary if access to the
  • 113. eld in changed to non-private I synthetic methods [JLS, ch. 13.1] are widely used, for instances when overriding methods with generic parameter types, and co-variant return types 74
  • 114. Summary I binary compatibility does not imply source compatibility (example: addtointerface) I binary compatibility does not imply binary behavioural compatibility (example: generics2) I source compatibility does not imply binary compatibility (example: specialiseReturnType1) I source compatibility does not imply source behavioural compatibility (example: generaliseParamType3) 75
  • 115. Ongoing Research and Open Questions I Empirical study on Qualitas Corpus on whether and how often these problems occur in real-world programs. Proceedings IEEE CSMR-WCRE 2014. Preprint: https://sites.google.com/site/jensdietrich/ publications/preprints I Quiz developers to
  • 116. nd out whether they are aware of this. Over 400 developers have responded,
  • 117. rst results here: https://sites.google.com/site/jensdietrich/ java-developer-survey-2013, preprint on arxiv: http://arxiv.org/pdf/1408.2607v1.pdf I Build better tools (better than clirr) to check library compatibility, infer semantic versioning info. Some ongoing work (Uni of Western Bohemia), more planned for later 2014. 76
  • 118. Acknowledgements I would like to thank Kamil Jezek who contributed Generics 1 and Static 1 and 2, Hussain Al Mutawa who pointed me to ghost references used in Ghost, and Alex Buckley for his comments and for contributing Adding a Method to an Interface. This work was inspired by Java Puzzlers by Joshua Bloch and Neal Gafter [PUZZ]. 77
  • 119. References JAPI Jim des Rivieres: Evolving Java-based APIs. http://wiki.eclipse.org/Evolving_Java-based_APIs JLS James Gosling, Bill Joy, Guy Steele, Gilad Bracha and Alex Buckley: The JavaTMLanguage Speci
  • 120. cation 7th Edition. JVMS Tim Lindholm, Frank Yellin, Gilad Bracha, and Alex Buckley. The JavaTMVirtual Machine Speci
  • 121. cation - JavaTMSE 7 Edition. PUZZ Joshua Bloch, Neal Gafter. Java Puzzlers. Addison-Wesley 2005. 78