Changing a constructor param type breaks class in another jar
binary-compatibility, binding, constructor, java, parameters
Solution
javac resolves exactly which method or constructor to call at compile time. This does not occur at link time. As the constructor signature has changed, the linking step cannot find the requested method and therefore throws an error. You can fix the error by providing to constructors - one which takes an `Collection` the other `List`. Later a constructor taking an `Iterable` could be added.
Note, generic types do not form part of the signature, so those can be changed whilst still keeping binary compatibility. Both parameter and return types form part of the signature for methods (covariant returns cause synthetic bridge methods to be created).
There is a nice big section in the JLS defining exactly what constitutes binary compatible changes.
Problem
I have the following class in a common jar: ``` public class Common { public Common(List list) { ... } } ``` I then change the constructor parameter from a `List` to a `Collection` as follows: ``` public class Common { public Common(Collection collection) { ... } } ``` Rebuilding the common jar and running the system causes a `NoSuchMethodError` in any dependent class when it invokes the constructor until I recompile that class. I've got a few ideas what's causing this, along the lines of how the constructor is bound in the bytecode of the dependent class, but I'm not 100% sure. Please can somebody shed some light onto what's going on here? Update I've subsequently done a quick test and taken a look at the bytecode: ``` Compiled from "Client.java" public class Client extends java.lang.Object{ public Client(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2; //class ArrayList 3: dup 4: invokespecial #3; //Method java/util/ArrayList."<init>":()V 7: astore_1 8: new #4; //class Common 11: dup 12: aload_1 13: invokespecial #5; //Method Common."<init>":(Ljava/util/List;)V 16: pop 17: return } ``` Like Tom said, and as you can see on line 13, the exact constructor is bound at compile time. You learn something new every day :-)