8
votes

From the description of SE_BAD_FIELD:

Non-transient non-serializable instance field in serializable class

This Serializable class defines a non-primitive instance field which is neither transient, Serializable, or java.lang.Object, and does not appear to implement the Externalizable interface or the readObject() and writeObject() methods. Objects of this class will not be deserialized correctly if a non-Serializable object is stored in this field.

Why is java.lang.Object an exception to the rule?

2
Maybe the authors expect that if you willfully choose java.lang.Object as the type of an attribute (the most general type, about which you cannot assume anything) instead of some specific type, you are already well aware that serialization cannot work reasonably with respect to that field. But I agree that the exception is strange: after all, the error might well be that you simply forgot the transient modifier! - Kilian Foth
It could have something to do with lock objects. - Matt

2 Answers

2
votes

Because everything can be deserialized back into an java.lang.Object as every class in java extends java.lang.Object. If you manage to serialize an object which has a non serializable field you have no way of knowing the class of that field on deserialization. Because every class is an object you can always fall back on the Object class.

    class NonSerializableUser {}
    class SerializableUser implements Serializable{}

    class SomeObject implements Serializable{
        public NonSerializableUser nonUser;
        public SerializableUser user;
        public Object nonUserObj;

        public SomeObject(SerializableUser u, NonSerializableUser uu, NonSerializableUser uuu){
            user = u;
            nonUser = uu;
            nonUserObj = uuu;
       }
    }

In this example deserializing this class would result in nonUser being null, user being the correct SerializableUser class instance, and nonUserObj would be non null however it will have lost all the NonSerializableClass methods and fields, they will not have been serialized. The only parts of that instance that get serialized are the methods and fields that belong to Object.

It's worth noting that a lot of serialization libraries (ObjectOutputStream for example) will complain about the non serializable class and won't serialize this object in the first place. This is why I left out the details of the serialization/deserialzation step. However a lot of xml frameworks will still serialize these classes and this tends to be the situation where this bug rears it's head.

2
votes

The number of false positives would be potentially high, as

public void writeIt(Object o, ObjectOutputStream oos) {
    oos.writeObject(o);
}

could be perfectly fine, as the caller always passes in an instance of a derived class that is Serializable.

Now the question is, why isn't the above method signature

public void writeIt(Serializable o, ObjectOutputStream oos) {
    oos.writeObject(o);
}

the answer is that then all kinds of objects defined by interfaces passed in as the first parameter would fail to compile.

such as

Map m = .....
writeIt(m, oos);

so the value of catching serializing java.lang.Object (which is probably an exceedingly rare event) is not worth the false positive impact.