I have a Serializable class (let's call it A) with a non-transient boolean field, and a subclass (B) for which that same field should be transient. How can I do this?
More precisely, I wish the field to be restored to the default boolean value (false
) when deserializing B, though I want it to be restored to the correct value when deserializing A. The other fields inherited from A should be restored nonetheless.
Functionnally, A represents an object which is restored between sessions, and B is a particular type of A whose state should be reset on each new session.
Quick code sample:
public class A implements java.io.Serializable {
private String label;
// non-transient
private boolean field;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public boolean isField() {
return field;
}
public void setField(boolean field) {
this.field = field;
}
}
public class B extends A {
// field should be transient for this class
// label should remain non-transient
}
An easy solution would be to change B extends A
to A extends B
, make the field transient, and add a writeObject()
to A to serialize the field. However, B extends A
has a functional meaning, and I am not convinced it would be wise to revert it.
I could implement a readObject()
method which would overwrite the deserialized value for the field. However, this feels like a dirty solution and I do not wish to use this unless no other choice is left.
I tried to write a writeObject()
method to emulate a transient field, but it does not work and I cannot tell why. If anybody has a clue, that might be my solution:
public class B extends A {
private void writeObject(ObjectOutputStream out) throws IOException {
// save current state
boolean field = isField();
// synchronized to make sure this instance is not interrogated
// while changed for serialization
synchronized (this) {
// emulate transient state and serialize
setField(false);
out.defaultWriteObject();
// restore state
setField(field);
}
}
}
public class B extends A {
// shadow A's field
private transient boolean field;
@Override
public boolean getField() {
return field;
}
@Override
public void setField(boolean field) {
this.field = field;
}
}
Following @m1o2's advice, I have been able to implement my solution using the Externalizable interface:
public class B extends A implements java.io.Externalizable {
// Do not forget to have a public no-arg constructor
// for Serialization to work
public B() {
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
// Write only the fields I am interested in
out.writeObject(getLabel());
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
// Read the serialized fields IN THE ORDER THEY WERE WRITTEN
setLabel((String) in.readObject());
}
}
Please note however that this is applicable because A and B are simple classes. For classes with many fields and a tendency to evolve, this could cost more (except maybe if using some code based on reflection).
If you don't care about the Superclass fields (all of them) you can use Externalizable interface
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