Java Serialization with Non Serializable Parts

Java Serialization with non serializable parts

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;
}
}

How to serialize a non-serializable 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.

  • First, make your non-serialisable field transient.
  • In writeObject, first call defaultWriteObject on the stream to store all the non-transient fields, then call other methods to serialise the individual properties of your non-serialisable object.
  • In readObject, first call defaultReadObject on the stream to read back all the non-transient fields, then call other methods (corresponding to the ones you added to writeObject) to deserialise your non-serialisable object.

I hope this makes sense. :-)

Java serialization of non serializable third party class

As I said in my comments, I'd go for a SerializationService which would find the proper Serializer<T> for every object you want to save.

Something like :

public interface Serializer<T> {

Serializable toSerializable(T objectToSerialize);

//to build a factory/service around it
boolean canDeserialize(Serializable serializedObject);

T fromSerializable(Serializable serializedObject);

}

And if you want a basic, concrete example : with the quite-common Path :

public class PathSerializer implements Serializer<Path> {

@Override
public Serializable toSerializable(Path objectToSerialize) {
return objectToSerialize.toString();
}

@Override
public Path fromSerializable(Serializable serializedObject) {
if(!canDeserialize(serializedObject)){
throw new IllegalArgumentException("Cannot deserialize this");
}
return Paths.get((String)serializedObject);
}

@Override
public boolean canDeserialize(Serializable serializedObject) {
return serializedObject != null && serializedObject instanceof String;
}

}

You could also very well store POJO containing the name your original object class and the list of parameters needed in its constructor an/or a map of its fields to be able to regenerate your objects by reflection.

It's all up to you and the complexity of your application.

Serializing an object which has a non-serializable parent class

The default value of a is 10 - it will be set to 10 when the object is created. If you want to have a realistic test, set it to a different value after instantiation and then serialize it.

As for your update - if a class is not serializable, its fields are not serialized and deserialized. Only the fields of the serializable subclasses.

Serialize hashmap with non-serializable objects

If you want to serialize objects than they must be Serializable.

Since a javafx.scene.control.Button is not serializable you must find another way to save the button's state somewhere else. E.g. by introducing a memento class that safes the state:

public class ButtonMemento implements Serializable {

private static final long serialVersionUID = 1L;

private boolean text;

/*
* Creates a memento that safes the given button's current state.
*/
public ButtonMemento(Button button){
this.text = button.getText();
// extend to record more properties of the button
}

/*
* Used to apply the current mementos state to a button
*/
public void applyState(Button button){
button.setText(text);
// extend to apply more properties to the button
}
}

The ButtonMemento class is a way to safe the state of an object that is not serializable and restore it later.

final HashMap<String, ButtonMemento> mapButton = new HashMap<>();

for(Button b : buttons){
String mapKey = ...;
mapButton.put(mapKey, new ButtonMemento(b));
}

try {
FileOutputStream fileOut = new FileOutputStream("Resources/");
ObjectOutputStream objStream = new ObjectOutputStream(fileOut);
objStream.writeObject(mapButton);
objStream.close();
fileOut.close();
System.out.println("Serialized HashMap mapButtons has been stored"
+ " in /tmp/store");
} catch (IOException i) {
i.printStackTrace();
}

Maybe you can implement somthing like a BeanMemento that can store the properties of a bean that are serializable and therefore can be used with every object that fulfills the java bean specification.

Java: What can and what can't be serialized?

When you are talking about NotSerializableException it is throw when you want to serialize an object, which has not been marked as Serializable - that's all, although when you extend non serializable class, and add Serializable interface it is perfectly fine.

There is no data that can't be serialized.



Related Topics



Leave a reply



Submit