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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With