Save not Serializable Collection to the file [duplicate] - java

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.

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

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.

If possible, the non-serialiable parts can be set as transient
private transient SomeClass myClz;
Otherwise you can use Kryo. Kryo is a fast and efficient object graph serialization framework for Java (e.g. JAVA serialization of java.awt.Color requires 170 bytes, Kryo only 4 bytes), which can serialize also non serializable objects. Kryo can also perform automatic deep and shallow copying/cloning. This is direct copying from object to object, not object->bytes->object.
Here is an example how to use kryo
Kryo kryo = new Kryo();
// #### Store to disk...
Output output = new Output(new FileOutputStream("file.bin"));
SomeClass someObject = ...
kryo.writeObject(output, someObject);
output.close();
// ### Restore from disk...
Input input = new Input(new FileInputStream("file.bin"));
SomeClass someObject = kryo.readObject(input, SomeClass.class);
input.close();
Serialized objects can be also compressed by registering exact serializer:
kryo.register(SomeObject.class, new DeflateCompressor(new FieldSerializer(kryo, SomeObject.class)));

If you can modify MyClass2, the easiest way to address this is declare the property transient.

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.

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.

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

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

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.

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

Related

Singleton Class Serialization

My singleton class be like this:
public class SerializableSingleton implements Serializable {
private static SerializableSingleton instance = new SerializableSingleton();
private SerializableSingleton() {
System.out.println("Constructor is being called");
}
public static SerializableSingleton getInstance() {
return instance;
}
}
Now it's written on the web that when we deserialize this singleton object, it will give a new instance back and not the previous one, and in order to fix this, use the readResolve() method.
But my question is - How is it even possible? When a static class member can't be serialized, how does the question of deserializing it comes at all? and it is all over the net?
Since the singleton object is static:
private static SerializableSingleton instance = new SerializableSingleton();
How is an instance getting serialized in the first place?
Serialization bypasses a lot of things in the language and even does some stuff that is not even possible with ordinary reflection.
When an object is serialized, it's class name and all instance fields (that are not transient) are written to the stream.
The magic happens when deserializing an object.
First, a new instance of the class is allocated.
To do that, the no-argument constructor of the first non-serializable superclass is called. The constructor of the serializable class (and serializable superclasses) are skipped. How? Magic.
Then all instance fields of the serializable classes are set.
(This step can be customized using a private void readObject(ObjectInputStream) method)
Lastly, a readResolve() method is called - if such a method exists. It's result is used as the result of deserializing the object.
(This does not apply to records, instances of java.lang.Class, java.lang.String, java.lang.Enum...)
In your example, this means that a new instance of your SerializableSingleton is created - bypassing your private constructor and instead calling java.lang.Object.<init>() - so you won't see the "Constructor is being called" output.
Now you have two instances of an "Singleton". To restore the original singleton semantics (there only ever exists one single instance of that class), we replace the just-deserialized-instance with the canonical instance:
private Object readResolve() {
return getInstance();
}
tl;dr: Java's serialization is complicated and sometimes indistinguishable to black magic. Using java's serialization opens the door to some surprising behaviors.
As the docs say:
By implementing the readResolve method, a class can directly control
the types and instances of its own instances being deserialized. The
method is defined as follows:
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
And:
... For example, a Symbol class could be created for which only a
single instance of each symbol binding existed within a virtual
machine. The readResolve method would be implemented to determine if
that symbol was already defined and substitute the preexisting
equivalent Symbol object to maintain the identity constraint. In this
way the uniqueness of Symbol objects can be maintained across
serialization.
And:
A writeObject method to control what information is saved ...
A readObject method [..] to read the information written ...
A writeReplace method to allow a class to nominate a replacement object to be written to the stream
A readResolve method to allow a class to designate a replacement object for the object just read from the stream
To get full control of Serialization (also to serialize static and transient fields) you have to implement the Externalization interface:
The writeExternal and readExternal methods of the Externalizable
interface are implemented by a class to give the class complete
control over the format and contents of the stream for an object and
its supertypes.
So writeReplace and readResolve methods give you some more control than the ordinary (and automated) serialization mechanism, that is, replace the object before/after serialization. and it is not urgently linked to Singleton serialization, but to fulfill the proxy pattern for serialization. But as you mentioned, this mechanism is also used to implement serialization of a Singleton.

How to serialize an object referencing a non-serializble object of generic type?

I have got an object which contains non serializable object inside.
class object BigObject<T extends smallObject> implements Serializable{
private T insideObject;
public BigObject(T insideObject) {this.insideObject = insideObject;}
}
I would like to serializable Big object, but I get java.io.NotSerializableException error for obvious reasons.
I read topics like:Java Serialization with non serializable parts
or https://dzone.com/articles/serializing-java-objects-non
The answers were very interesting, but could not resovle my problem.
First of all insideObject is a class from a library, co I cannot add serializable implementation.
The answer given on the dzone webpage is also interesting (to write your own writeObject methods).
But as you can see, insideObject is a generic class, we can get a few types of insideObject extending on smallObject in bigObject, so this solution is impossible.
So, is it possible to manage with this problem in the other way?
Maybe I can somehow add implementation of serializable on the existing object? Or only external liblaries as Kyro can help me with my problem?
You should try to implement Externalizable Interface rather than Serializable
Then you need to override the writeExternal and readExternal method of Externalizable
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(urObject);
}
This is why java has Transient keyword right?
Declare the variable which is non serializable as transient and your problem will be solved.
i.e.
private transient T insideObject;
Use transient before any field that you don't want to be incorporated into a serialisation.
Standard serialisers will pass over that field.
I think the example from dzone is something that can help you.
One approach is to use BigObject as an abstract base class and create subclasses for each case of smallObject that handles their own serialization/desearialization logic following the example you posted.
The other is sticking to a single BigObject class, but, during the serialization you can also serialize the class name of the concrete smallObject instance. Then during deserialization, you can modify the logic accordingly.
private void writeObject(final ObjectOutputStream out) throws IOException {
out.writeUTF(this.insideObject.getClass().getCanonicalName());
// serialize this.insideObject
}
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
String insideClassName = in.readUTF();
// choose logic based on class name
}
I would personally go with the first approach, since it will keep the code cleaner and stick to OOP best practices.

Serializing a class containing a non-serializable class

I have two classes, A and B.
Class A is developed by X company and is not serializable.
Company Y is trying to use class A in class B, which must be serializable.
How can this be done without changing class A? Is that what the externalization interface is for?
Sure. You need to make fields in your class B referring to their class A transient (or use serialPersistentFields if I've spelt that correctly). Implement custom writeObject and readObject methods in B to save the required state of A in serialisable objects.
There is no need for Externalizable (pretty much ever).
As pointed out by #Tom Hawtin - tackline You have two ways to combat this situation:
1. Declare the instance variable of class A as transient..
private transient A a ;
Or,
2. By using serialPersistentFields. This instructs the JVM to persist only those fields which it has mentioned. Here is a short example:
public class B implements Serializable
{
private A a;
private String name ;
private int enrollment;
private static final ObjectStreamField[] serialPersistentFields =
{
new ObjectStreamField("name",String.class),
new ObjectStreamField("enrollment",int.class)
}; //This will cause only "name" and "enrollment" to persist while serialization
}
Yes, this can be done by implementing java.io.Externalizable - it allows you to implement serialization manually, by writing individual bytes (or more conveniently through methods like writeInt()). As long as you can get and set all information about an instance of class A from its public API, you can simply embed it into your custom serialized representation of classs B.

Java Serialization and JavaBeans

Quick question, when marking an object as serializable, does it need to be a JavaBean? I mean, can you serialize an object that's not a JavaBean? Does it have any risk? Is it a good practice to always make an object a JavaBean if you intend to serialize it?
You are looking at it the wrong way. A Java Bean is any class that is
1) implements Serializable
2) Has a no-arg constructor
3) Has private members and setters/getters
So your question
marking an object as serializable, does it need to be a JavaBean?
has it backwards. Any class can be Serializable, by implementing the interface. Not all serializable classes define a Java Bean.
I mean, can you serialize an object that's not a JavaBean?
Yes.
Is it a good practice to always make an object a JavaBean if you
intend to serialize it?
It is good practice to design your classes with data encapsulation in mind. This means limiting access to fields directly, and using setters and getters where appropriate.
Of course, having a public no-arg constructor is not always necessary from an API point of view.
You really only need to follow the Java bean standard if you are going to use a library that depends on your classes being Java Beans.
Serializable is a marker Interface. Each Object you mark with the serializable interface can be sent trouh the wire or can be safed in a file. For example if you mark the class Foo with the serializable interface, you are able to safe the object state in a file and restore it later:
public class Foo implements java.io.Serializable{
public String name;
}
public main(){
Foo foo = new Foo();
foo.name="test";
try
{
FileOutputStream fileOut = new FileOutputStream("foo.file");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(foo);
}
}
That means it doesnt need to be a JavaBean. It could be a plain old java object, like the Foo Object example.
If you want to serialize an object of class, then that class need to implement serializable interface irrespective of it's bean (or) class with simple properties.
To serialize an object means to convert its state to a byte stream so that the byte stream can be reverted back into a copy of the object. A Java object is serializable if its class or any of its superclasses implements either the java.io.Serializable interface or its subinterface, java.io.Externalizable. Deserialization is the process of converting the serialized form of an object back into a copy of the object
This tutorial may help you
You can serialize any object that implements the Serializable interface, whether it's a JavaBean or not.
That said, the decision to make an object Serializable shouldn't be made lightly, because it locks in certain implementation details of the class thus reducing future flexibility.
See here for information on implementing Serializable.

Serialising and immutable objects

I have a class which is intended for immutable use, hence I would like to label all the fields final.
However the class is serialized and deserialized to send over the network. For this to work an empty constructor is required. This prevents me creating the final fields.
I'm sure this is a fairly common problem but I can't find a solution. How should I proceed?
A no-arg constructor is not required. The most derived non-serialisable class does need a no-arg constructor available to the least-most derived serialisable class.
If you need to mutate fields inside a readObject, then use a serial proxy through readResolve and writeReplace.
In the typical serialization case, it is not required that class have an empty constructor or non-final fields to be serializable.
Now, if you have to do your own serialization, or you need to subclass a class that doesn't implement Serializable, that is a different story.
So you need to provide some more details of how you are having a problem.
This issue is an open bug on the Java language. (Note that this only applies if you have to do the serialization manually, such as with readObject)
To echo what has been said, no-arg constructors are not a requirement if you are taking the route of implementing the java.io.Serializable interface. Take a look at the java.lang.Integer source code for example, a simple serializable/immutable class that has two constructors: one that takes an int, and one that takes a String. Source code: http://www.docjar.com/html/api/java/lang/Integer.java.html. Javadoc: http://java.sun.com/javase/6/docs/api/java/lang/Integer.html.
Also depending on the complexity of your class and what you are doing, you could consider implementing serialization via the java.io.Externalizable interface (although some consider it outdated, and it DOES require a no-arg constructor). Here's an overview on SO: What is the difference between Serializable and Externalizable in Java?, and here's the official Java tutorial: http://java.sun.com/docs/books/tutorial/javabeans/persistence/index.html.
For the record, since I had a similar issue:
I had a message "java.io.InvalidClassException: com.example.stuff.FooBar; com.example.stuff.FooBar; no valid constructor"
I thought it was because it was lacking a default constructor. But the above answers confirm it is not mandatory (but our app. uses an old serializer that indeed require a default constructor, so the case can arise).
Then I found a page stating:
If a class that is designed for inheritance is not serializable, it
may be impossible to write a serializable subclass. Specifically, it
will be impossible if the superclass does not provide an accessible
parameterless constructor.
Hence the message I got, I suppose. It appeared that the core issue was classical: I declared a class as serializable, but the superclass was not! I moved the Serializable interface up in the hierarchy, and all was well.
But the message was a bit misleading... :-)
A no-arg constructor is not required. Let's read the source code:
// java.io.ObjectStreamClass
private static Constructor<?> getSerializableConstructor(Class<?> cl) {
Class<?> initCl = cl;
while (Serializable.class.isAssignableFrom(initCl)) {
if ((initCl = initCl.getSuperclass()) == null) {
return null;
}
}
...
}
So, actually the no-arg constructor is required in the nearest not Serializable class in the type hierarchy.
It means the following class Domain can be serialized.
class Domain implements Serializable {
private final int a;
public Domain(int a) {
this.a = a;
}
}
But the class Son can't:
class Father{
private final int a;
public Father(int a) {
this.a = a;
}
}
class Son extends Father implements Serializable {
public Son(int a) {
super(a);
}
}

Categories