Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Serialization with non serializable parts

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.

like image 529
Burkhard Avatar asked Sep 18 '08 18:09

Burkhard


People also ask

Can we serialize a non-serializable object in Java?

You can't serialise a class that doesn't implement Serializable , but you can wrap it in a class that does. To do this, you should implement readObject and writeObject on your wrapper class so you can serialise its objects in a custom way.

Can serializable class contain non-serializable field in Java?

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.)

What if serializable class contains non-serializable fields?

The class will not be serialisable, unless the field is declared transient (which will prevent the field from being serialised, i.e. it will not be saved).

What are non-serializable objects in Java?

In Java, a NotSerializableException exception is thrown when an instance of a class must implement the Serializable interface. The exception is thrown by either the serialization runtime, or by the instance of the class. The argument for the NotSerializableException is the name of the class.

How to serialize an object in Java?

For serializing the object, we call the writeObject () method of ObjectOutputStream class, and for deserialization we call the readObject () method of ObjectInputStream class. We must have to implement the Serializable interface for serializing the object. Advantages of Java Serialization

How do I serialize a non-serializable class?

Wrap the non-serializable class in a class of your own that implements Serializable. In your class's writeObject method, do whatever's necessary to serialize sufficient information on the non-serializable object so that your class's readObject method can reconstruct it.

What is deserialization in Java?

Deserialization is the process of reconstructing the object from the serialized state. It is the reverse operation of serialization. Let's see an example where we are reading the data from a deserialized object. If a class implements Serializable interface then all its sub classes will also be serializable.

What is custom serialization?

Specifically, as will be demonstrated in this post, custom serialization can be used to allow a larger object to be serialized even when attributes of that object are not themselves directly serializable.


2 Answers

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;
  }
}
like image 186
Scott Bale Avatar answered Oct 14 '22 04:10

Scott Bale


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.

like image 36
Mike Deck Avatar answered Oct 14 '22 02:10

Mike Deck