views:

103

answers:

3

In Java, I define an abstract class with both concrete and abstract methods in it, and it has to be subclassed independently by third-party developers. Just to be sure: are there any changes I could make to the abstract class that are source compatible with their classes but not binary compatible? In other words: after they have compiled their subclasses, could I change the abstract class - apart from e.g. adding an abstract method to it or removing a protected method from it that is called by subclasses, which are of course source incompatible - in a way that could force them to recompile their subclasses?

+2  A: 

Sure.

You can accidently use a method name that they've used, which is now suddenly overridden, with perhaps dramatically different results.

You can add fields to the class which mess up serialization etc.

Will Hartung
+5  A: 

If it isn't too late to change your system, I would suggest that you do that. Overriding is usually not a good way to customize functionality, as it is incredibly fragile. For example, if you later use a method name that your clients have used (which they are now unintentionally automatically overriding), then it is possible that the override will completely break the invariants of your class. A usually better way of providing customization is to give your clients an interface which is limited to just the customized behavior, and then you have a fully concrete class that depends on an instance of this interface, and delegates appropriately to the interface when it needs to use the customized behaviors. This way, your code and your client's code are completely separated, and they won't interfere with each other.

Michael Aaron Safyan
Thanks for also providing the alternative! That was also what I was considering - I was weighing its costs in complexity (maintaining a reference to the implementation and delegating to it) but since this pluggable architecture is a requirement, I'll do this.
thSoft
+3  A: 

I am assuming that you are using "binary incompatibility" in the technical sense; e.g. where the classloader detects the incompatibility and refuses to load the classes.

Binary incompatibility could also be introduced if you added a visible method and declared it final, and that method collided with the signature of some existing method in a third-party subclass. However, if the method is non-final, the existing method will turn into an override of your (new) method which might cause problems ... but not binary incompatibility.

Likewise, adding new visible fields will result in hiding, may result in confusing behavior and will break object serialization. But this will not result in binary incompatibility.

In general this points to the fact that you need to consider application semantic issues as well as simple binary compatibility. And the Java type system won't help you there.

For completeness, there are a other things that you could do in your code that would break binary compatibility for the 3rd party classes:

  • reduce the visibility of your abstract class and/or its methods,
  • change the signatures of other classes used as parameter result and exception types,
  • change the chain of superclasses that your abstract class extends, or make an incompatible change in those classes, or
  • change the tree of interfaces that your abstract class implements, or make an incompatible change in those interfaces.
Stephen C
Thanks for the comprehensive answer, and for thinking of what I also thought of but did not describe, namely any other ways to break the implementors' code.
thSoft