Serializing a class containing a non-serializable class - java

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.

Related

Why implement Serializable on models?

I noticed in Spring-boot a lot of people create models/entities and implement the Serialiazable interface.
public class ModelBase implements Serializable
I understand what it means to serialize data/classes as it enables you to save the state of a class (if I'm not wrong, to a file for instance).
But I believe this should be done only when necessary, but either way it seems people just tend to implement the interface.
Is there a different reason?
When your models or entities are meant to travel across several JVM's then you might want to consider implementing Serializable interface. You should do this with caution. You should also provide a a valid UUID for the class to be used during Serialization and vice versa.
Sample is
private static final long serialVersionUID = 9178661439383356177L;
And
According to JPA Spec:
If an entity instance is to be passed by value as a detached object (e.g., through a remote interface), the entity class must implement the Serializable interface.
Also
When using serializable values it is possible to remove this redundancy by changing the entity class in two ways:
Make the entity class serializable, so it can be used in place of the value class.
Make the key fields transient, so they are not redundantly stored in the record.
https://docs.oracle.com/cd/E17277_02/html/collections/tutorial/SerializableEntity.html

Why to serialize model class

Many times I see a model class will implement Serializable, but is never serialized.
What is purpose here to implement Serializable?
If serialization is not used, what will I miss? Is there any effect in the way the code communicates?
public class Stock implements Serializable{
private int stockId;
private String stockCode;
private String stockName;
//Getter and setter
}
What is purpose here to implement Serializable?
Just a marker to indicate the possibility provided to clients of the class for serializing instances of them if they wish.
For example, if you instantiate Stock class and that you want to save Stock instances in a file, you can do it thanks to this marker. APIs (for example Jaxb or Java native serialization mechanism) rely generally on the implementation of this interface to serialize class.
If serialization is not used, what will I miss? Is there any effect in
the way the code communicates?
It's is not used, you have zero overhead or transformation in the communication of the instance since it is a marker interface. Only, when the serialization occurs, the communication of the instance changes.
Serializable is just a marker interface without overhead*.
If you want class A to implement serializable and class A contains field with type Stock, Stock should also implement serializable.
May be there will be no direct Stock class instance serializations. But it will be serialized via class A instance.
Also implementing is necessary if you want Stock instance to become an argument of
type foo(? extends Serializable param)

Will objects of a custom class, inside an array, keep their data after serialization?

I am building a small application for keeping statistical data of some sort. I have a general question, before I start coding hard in this matter.
Say we have an object X of its own class, representing a sports match. It has several fields, among which is another object Y - also it's own class. Y will represent stats for a given game. The structure should be something like:
class Match {
Date date;
String venue;
ArrayList<Game>[10] gameList;
...
}
class Game{
int result;
int blah blah;
...
}
If I go and create a couple of Match objects, stored in an array for example, i can serialize an object, that contains this array of Matches, but when i deserialize it back, will I be able to keep the data inside the Game objects for example? Do I need to make each class used Serializable?
The reason for my worries are those lines from the JAVA Api Documentation:
During deserialization, the fields of non-serializable classes will
be initialized using the public or protected no-arg constructor of the
class. A no-arg constructor must be accessible to the subclass that is
serializable. The fields of serializable subclasses will be restored
from the stream.
When traversing a graph, an object may be encountered that does not
support the Serializable interface. In this case the
NotSerializableException will be thrown and will identify the class of
the non-serializable object.
Yes, you need to make Match class serializable. Making a class serialize means that you need to make all instance variables of that class serializable too (notice the recursive definition). In your example, to make Match class serializable, you need to make Game class serializable.
i guess the term
non-serializable classes
means such class doesn't implements the serializable interface there's exist classes in java doesn't implement serializable interface and you can't serialize them for example java.awt.BasicStroke you can't serialize any instance of of this class directly

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