Resolved: interfaces should not implement Serializable

I’ve been trying to clean up the serialization story in Jaxen lately. Bottom line is that you really shouldn’t just willy-nilly declare that classes and interfaces implement Serializable. Getting serialization right is not hard, but it is tedious, and it needs to be thought about and tested. There’s a lot more to it than just adding implements Serializable to every class.

After I filed one bug, the usually reliable Brian Ewins made the comment that, “I also thought it was considered best practice not to declare interfaces serializable.” That sounds plausible, but I can’t really figure out why, nor can I make strong case for the opposite position. So here’s the question. Given an interface Foo is it or is it not a good idea to declare that Foo implements Serializable? (given that you do in fact want the instances to be serializable, of course.) Or should one leave implements Serializable off the interface and just place it on the concrete classes? Why or why not?

A slightly less boolean variant of this question: when should one mark the interfaces Serializable and when should one mark the implementation classes Serializable?

The only reason I can come up with is that since most of the work of making a class serializable (calculating a serialVersionUID, providing custom readObject() and writeObject() methods, marking fields transient, etc.) you don’t want to declare that something implements Serializable until you know that work has been done. If the interface declares that it implements Serializable, then the implementations are likely to happen by accident, and the necessary work won’t get done. This leads to fragile, brittle, and broken serialized forms. That makes sense, but it doesn’t feel like a very string argument. Can anyone suggest a better reason why one should or should not declare an interface Serializable? Comments are open.

8 Responses to “Resolved: interfaces should not implement Serializable”

  1. John Cowan Says:

    I think you are quite right, but I would put the argument another way (hopefully clearer):

    What is in fact serializable is not a class or an interface but an instance. Classes have instances, so it makes sense to say that the instances of SomeClass extend Serializable. Interfaces as such don’t have instances (instances conform to interfaces), so it does not make sense.

    For SomeInterface to extend Serializable is essentially to demand that any class extending SomeInterface have serializable instances. Unfortunately, since Serializable is a marker interface, there is no way for the compiler to check whether the instances are truly serializable or not. Therefore, having SomeInterface extend Serializable makes promises that may or may not be kept.

    Exactly the same arguments apply to Cloneable, to the nonstandard interface Immutable, and indeed to any other marker interface. In any case, the only operation you can perform on a marker interface is to ask whether an object is an instance of it, a function which can now be performed better with annotations. IMHO, annotations should supersede marker interfaces in future designs.

  2. John Cowan Says:

    Er, for “extending SomeInterface” read “implementing SomeInterface”, of course. You really need a “Preview Comment” button.

  3. Alex Blewitt Says:

    Getting serializable right may be difficult, but getting it wrong is easy. Anything that isn’t serializable can’t be used in a serializable mechanism, and you only need one tooth breaking off a cog to make an entire machine grind to a halt.

    If you’ve got control over both the client and the server, then it’s not really much of an issue — if you get a serialisation error, then you update the classpath on both and bounce. If you’re dealing with a more separated system where you maybe don’t have control, you probably shouldn’t be using serialization anyway, and using something independent like XML to transfer data.

    If your interface is something that needs to be used in a Serializable context, then marking that interface extend Serializable is a good way of enforcing the contract to implementors of that interface. Let’s face it, if you have a method called bar() in the interface, you’re expecting that classes that implement the interface called bar() do it properly, right? And if it was a super interface that defined foo() (which the class also had to implement) that it would do it correctly too, that it would also be done properly? Or implementing toString() or equals() that come from a superclass?

    So why is it any different from Serializable, just because there’s no method? You’re stating a requirement by implementing the interface, and subclasses should respect that. If they don’t, they are broken.

  4. Horaci Says:

    I see Serializable as an implementation detail and not part of the contract a class should adhere to.
    As such I wouldn’t use Serializable in an interface; I’d use it in a class. I’d think the same applies to synchronized methods on interfaces.

    Maybe the line between what’s contract and what’s implementation is not always clear, but given marking an interface Serializable doesn’t give you any guarantees about the classes implementing it I would prefer not to use it at all.

    So how can an application enforce 3rd party implementations of APIs are serializable ? They just can’t do it at compile time. All they can do is try to handle NotSerializableExceptions if the class doesn’t implement Serializable or just fail if class does implement Serializable but hasn’t coded properly for serialization. In any case it won’t be the application’s problem if an implementation is broken.

  5. Horaci Says:

    I wrote another comment suggesting “I’d think the same applies to synchronized methods on interfaces” should be “I’d think the same applies to synchronized keyword on overrideable methods”, as interfaces don’t allow synchronized keyword.

    This comment seems to be lost, although I could see it in the website right after adding it… am I missing something here ?

  6. Elliotte Rusty Harold Says:

    Possibly I accidentally deleted your comment while cleaning spam. That’s been happening a lot lately. I’m working on a more reliable spam filtering solution.

  7. sporadic reader Says:

    Elliotte, please note :

    1. Classes IMPLEMENT interfaces
    2. Interfaces EXTEND interfaces

  8. Aoi Says:

    syntactically yes transient can be used with satitc but there is no point of doing that as transient keyword is used to prevent any field from serialization and are not serialized anyway. By the way thanks for bringing this point.