views:

4002

answers:

10

I have:

class MyClass extends MyClass2 implements Serializable {
  //...
}

In MyClass2 is a property that is not serializable. How can I serialize (and de-serialize) this object?

Correction: MyClass2 is, of course, not an interface but a class.

A: 

Well, since you can't implement a class and interfaces can't have fields, I think you're probably "A-OK". :-)

Daniel Spiewak
A: 

MyClass2 is just an interface so techinicaly it has no properties, only methods. That being said if you have instance variables that are themselves not serializeable the only way I know of to get around it is to declare those fields transient.

ex:

private transient Foo foo;

When you declare a field transient it will be ignored during the serialization and deserialization process. Keep in mind that when you deserialize an object with a transient field that field's value will always be it's default (usually null.)

Note you can also override the readResolve() method of your class in order to initialize transient fields based on other system state.

Mike Deck
+5  A: 

You will need to implement writeObject() and readObject() and do manual serialization/deserialization of those fields. See the javadoc page for java.io.Serializable for details. Josh Bloch's Effective Java also has some good chapters on implementing robust and secure serialization.

sk
That's assuming MyClass2 doesn't contain state which inherently can't be serialized. It might just be impossible.
Steve Jessop
+1  A: 

You can start by looking into the transient keyword, which marks fields as not part of the persistent state of an object.

Hank
+2  A: 

declare your property transient and it won't be serialized.

class MyClass extends MyClass2 implements Serializable {
  private transient Object noSer;
}
ykaganovich
+1  A: 

XStream is a great library for doing fast Java to XML serialization for any object no matter if it is Serializable or not. Even if the XML target format doesn't suit you, you can use the source code to learn how to do it.

Boris Terzic
+4  A: 

Depends why that member of MyClass2 isn't serializable.

If there's some good reason why MyClass2 can't be represented in a serialized form, then chances are good the same reason applies to MyClass, since it's a subclass.

It may be possible to write a custom serialized form for MyClass by implementing readObject and writeObject, in such a way that the state of the MyClass2 instance data in MyClass can be suitably recreated from the serialized data. This would be the way to go if MyClass2's API is fixed and you can't add Serializable.

But first you should figure out why MyClass2 isn't serializable, and maybe change it.

Steve Jessop
+4  A: 

As someone else noted, chapter 11 of Josh Bloch's Effective Java is an indispensible resource on Java Serialization.

A couple points from that chapter pertinent to your question:

  • assuming you want to serialize the state of the non-serializable field in MyClass2, that field must be accessible to MyClass, either directly or through getters and setters. MyClass will have to implement custom serialization by providing readObject and writeObject methods.
  • the non-serializable field's Class must have an API to allow getting it's state (for writing to the object stream) and then instantiating a new instance with that state (when later reading from the object stream.)
  • per Item 74 of Effective Java, MyClass2 must have a no-arg constructor accessible to MyClass, otherwise it is impossible for MyClass to extend MyClass2 and implement Serializable.

I've written a quick example below illustrating this.


class MyClass extends MyClass2 implements Serializable{

  public MyClass(int quantity) {
    setNonSerializableProperty(new NonSerializableClass(quantity));
  }

  private void writeObject(java.io.ObjectOutputStream out)
  throws IOException{
    // note, here we don't need out.defaultWriteObject(); because
    // MyClass has no other state to serialize
    out.writeInt(super.getNonSerializableProperty().getQuantity());
  }

  private void readObject(java.io.ObjectInputStream in)
  throws IOException {
    // note, here we don't need in.defaultReadObject();
    // because MyClass has no other state to deserialize
    super.setNonSerializableProperty(new NonSerializableClass(in.readInt()));
  }
}

/* this class must have no-arg constructor accessible to MyClass */
class MyClass2 {

  /* this property must be gettable/settable by MyClass.  It cannot be final, therefore. */
  private NonSerializableClass nonSerializableProperty;

  public void setNonSerializableProperty(NonSerializableClass nonSerializableProperty) {
    this.nonSerializableProperty = nonSerializableProperty;
  }

  public NonSerializableClass getNonSerializableProperty() {
    return nonSerializableProperty;
  }
}

class NonSerializableClass{

  private final int quantity;

  public NonSerializableClass(int quantity){
    this.quantity = quantity;
  }

  public int getQuantity() {
    return quantity;
  }
}
Scott Bale
A: 

A useful approach for serialising instances of non-serializable classes (or at least subclasses of) is known a Serial Proxy. Essentially you implement writeReplace to return an instance of a completely different serializable class which implements readResolve to return a copy of the original object. I wrote an example of serialising java.awt.BasicStroke on Usenet

Tom Hawtin - tackline
A: 

Several possibilities poped out and i resume them here:

  • Implement writeObject() and readObject() as sk suggested
  • declare the property transient and it won't be serialized as first stated by hank
  • use XStream as stated by boris-terzic
  • use a Serial Proxy as stated by tom-hawtin-tackline
Burkhard