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

If the Serializable interface is just a Marker-Interface that is used for passing some-sort of meta-data about classes in java - I'm a bit confused:
After reading the process of java's serialization algorithm (metadata bottom-to-top, then actual instance data top-to-bottom), I can't really understand what data cannot be processed through that algorithm.
In short and formal:
What data may cause the NotSerializableException?
How should I know that I am not supposed to add the implements Serializable clause for my class?

First of all, if you don't plan to ever serialize an instance of your class, there is no need to even think about serializing it. Only implement what you need, and don't try to make your class serializable just for the sake of it.
If your object has a reference (transitive or direct) to any non-serializable object, and this reference is not marked with the transient keyword, then your object won't be serializable.
Generally, it makes no sense to serialize objects that can't be reused when deserialized later or somewhere else. This could be because the state of the object is only meaningful here and now (if it has a reference to a running thread, for example), or because it uses some resource like a socket, a database connection, or something like that. A whole lot of objects don't represent data, and shouldn't be serializable.

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.

Anything your Serializable class has in it that is not Serializable will throw this exception. You can avoid it by using the transient keyword.
Common examples of things you can't serialize include Swing components and Threads. If you think about it it makes sense because you could never deserialize them and have it make sense.

All the primitive data types and the classes extend either Serializable directly,
class MyClass extends Serializable{
}
or indirectly,
class MyClass extends SomeClass{
}
SomeClass implements Serializable.
can be serialized. All the fields in a serializable class gets serialized except the fields which are marked transient. If a serializable class contains a field which is not serializable(not primitive and do not extend from serializable interface) then NotSerializableException will be thrown.
Answer to the second question : As #JB Nizet said. If you are going to write the instance of a class to some stream then and then only mark it as Serializable, otherwise never mark a class Serializable.

You need to handle the serialization of your own Objects.
Java will handle the primitive data types for you.
More info: http://www.tutorialspoint.com/java/java_serialization.htm

After reading the process of java's serialization algorithm (metadata bottom-to- top, then actual instance data top-to-bottom), I can't really understand what data cannot be processed through that algorithm.
The answer to this is certain system-level classes such as Thread, OutputStream and its subclasses which are not serializable. Explained very well on the oracle documents: http://www.oracle.com/technetwork/articles/java/javaserial-1536170.html
Below is the abstract:
On the other hand, certain system-level classes such as Thread, OutputStream and its subclasses, and Socket are not serializable. Indeed, it would not make any sense if they were. For example, thread running in my JVM would be using my system's memory. Persisting it and trying to run it in your JVM would make no sense at all.

NotSerialisable exception is thrown when something in your serializable marked as serializable. One such case can be:
class Super{}
class Sub implements Serializable
{
Super super;
Here super is not mentioned as serializable so will throw NotSerializableException.

More practically, no object can be serialized (via Java's built-in
mechanism) unless its class implements the Serializable interface.
Being an instance of such a class is not a sufficient condition,
however: for an object to be successfully serialized, it must also be
true that all non-transient references it holds must be null or refer to
serializable objects. (Do note that that is a recursive condition.)
Primitive values, nulls, and transient variables aren't a problem.
Static variables do not belong to individual objects, so they don't
present a problem either.
Some common classes are reliably serialization-safe. Strings are
probably most notable here, but all the wrapper classes for primitive
types are also safe. Arrays of primitives are reliably serializable.
Arrays of reference types can be serialized if all their elements can be
serialized.

What data may cause the NotSerializableException?
In Java, we serialize object (the instance of a Java class which has already implemented the Serializable interface). So it's very clear that if a class has not implemented the Serializable interface, it cannot be serialized (then in that case NotSerializableException will be thrown).
The Serializable interface is merely a marker-interface, in a way we can say that it is just a stamp on a class and that just says to JVM that the class can be Serialized.
How should I know that I am not supposed to add the implements
Serializable clause for my class?
It all depends on your need.
If you want to store the Object in a database, you can
serialize it to a sequence of byte and can store it in the
database as persistent data.
You can serialize your Object to be used by other JVM working
on different machine.

Related

Can I clone an object if I have access only to its interface and is not serializable?

I have the interface of an object. I don't know if the implementation is serializable or not. Nor Cloneable.
And I don't have getters of object properties, actually, I don't know the properties either.
Can I still clone the object?
I mean, can I do something like:
public void copyMyObject(MyObject myObject){
this.copyOfMyObject = ...//? can I make a deep copy?
}
I guess not...but maybe I am missing something.
Well ... it depends.
You can serialize an object if the object's actual class implements Serializable ... and the rest1. The actual type may be different to the (static) type of the variable where you are getting the object's reference from.
But if not, then you are not missing something. Deep copying an object that doesn't implement its own deep copy methods, getters and setters, or some form of serialization, would involve some extremely nasty coding2.
You are better off designing your classes so that they can be serialized / cloned. Or, so that you don't need to clone them.
Note that there are a few Java classes that would be impossible to clone correctly even by "nasty" means. Examples include Thread, Socket, Class, ClassLoader and some key awt classes. So if your (hypothetical) application design depended on (say) being able to clone a running thread, that design would not be implementable.
1 - Instance fields that are not transient and not null need to be serializable as well. And so on.
2 - For example, you could conceivably make use of abstraction breaking reflection and use of the Unsafe to replicate what the object serialization implementation does under the hood ... without the Serializable type check. It is a bad idea though.

RMI marshal and serialization

In java using RMI to marshal an object that you are returning from the remote class do you just need to implement Serializable on that object? I have a class node with variables inside that i want to be returned. Do i just implement serializable? If so what about the class that is receiving the object? does its class need to implement serializable too?
example:
public class node implements Serializable{
//variables
//variables
public node(//arguments to constructor here){
}
}
The class that is being serialized needs to implement Serializable. The sending and receiving classes don't. Not sure why you would think otherwise.
If you have a class whose instances you want to serialize using built-in Java serialization, not only must it implement Serializable, all its instance variables must also implement Serializable, or be primitives, or be marked transient (i.e. you tell the JVM that it's okay for them to not get serialized).
If your class can't conform to these constraints for some reason, you can implement custom serialization behavior yourself by implementing Externalizable - then you take responsibility for writing out your object's state and reading it back on the other end.
I'm not sure whether I understand your question correctly or not, but ... if the serializable class has other objects as member variables, then better make them serializable also, otherwise better declare as transient to skip. does this answer your question?
if code inspector program is handy, you can have answer for such question very quickly without posting it
for your tip, only the object you wan to persist or transfer needs to implements Serializable, so the object can be reconstructed as the class structure through serializing/unserializing

ObjectOutputStream doesn't correctly save fields of superclasses unless they're Serializable, why no error or warning?

Say I have an ArrayList<B> array of objects from a certain class B, which extends A. B has an instance field bb and A a field aa. I know that saving array to a .dat-file using ObjectOutputStream requires that B (not just ArrayList!) implement Serializable. I've found, however, that when loading the object back from the file (using an ObjectInputStream):
arrayLoaded = (ArrayList<B>)myObjIn.readObject();
the loaded array isn't identical to the original array: In the particular case, arrayLoaded.get(0).bb has the same value as in array, but arrayLoaded.get(0).aa is "zeroed". It has a default initialization value, regardless of its value when array was saved to file. However, this problem is solved by letting also A implement Serializable.
What bothers me is that this error is so subtle: no exception, no warning (in eclipse), nothing. Is there a reason for this or is this simply an oversight by the java developers? Do I just have to accept it and think hard about which classes in the hierarchy implement Serializable every time I want to use object IO streams?
Just because B implements Serializable, that does not retroactively include the fields of the non-serializable superclass in what gets serialized. (This makes sense, especially when you consider that being able to serialize private and package-private fields of any class just by extending it and implementing Serializable would violate its encapsulation.)
A field declared in A will behave the same as a field declared as transient in B. There is a workaround however. From the documentation for Serializable:
To allow subtypes of non-serializable classes to be serialized, the
subtype may assume responsibility for saving and restoring the state
of the supertype's public, protected, and (if accessible) package
fields. The subtype may assume this responsibility only if the class
it extends has an accessible no-arg constructor to initialize the
class's state.
So you will need to implement writeObject and readObject in B to handle the serialization/deserialization of A.aa.
What bothers me is that this error is so subtle: no exception, no warning (in eclipse), nothing. Is there a reason for this or is this simply an oversight by the java developers?
It is by design. (See #Paul Bellora's answer). The alternatives would be to:
Make it illegal to declare a class Serializable unless its superclass is Serializable. That's obviously unworkable.
Automatically serialize the superclasses fields which breaks if the should or can't be serialized. (Note that we can't rely on transient here, because if the designer of the superclass didn't intend the it to be serializable, he/she won't have labelled the fields.)
Do I just have to accept it and think hard about which classes in the hierarchy implement Serializable every time I want to use object IO streams?
Basically, yes. In particular, you need to think hard when you write a Serializable subclass of an existing non-Serializable class.
I guess it is possible to write FindBugs / PMD / etc rules to flag this particular usage as potentially problematic.

Why does implementing Externalizable need a default public constructor?

We don't need it if we're implementing Serializable. So why this difference? How does it relate to the actual mechanism of Serialization?
A thorough explanation (although the grammar of the article might be improved) can be found on http://www.jusfortechies.com/java/core-java/externalization.php . The short answer, for future reference in case the linked page goes away:
Externalizable is an interface extending Serializable. Contrary to Serializable, though, objects are not restored by just reading the serialized bytestream, but the public constructor is called and only once the object is thus created, its state is restored. This makes restoring more efficient.
Edit: See also What is the difference between Serializable and Externalizable in Java? .
This is primarily used for caching purposes. In order to deserialize across streams, you will need to spell out how you want your object to be deserialized, hence the two methods provided by the contract in Externalizable interface: writeExternal and readExternal. Note that Externalizable extends Serializable, so you don't necessarily need to implement Serializable interface (although it's a marker interface and there are no methods to be actually implemented).
For a sample implementation, have a look at MimeType.
A public no-arg constructor is needed while using Externalizable interface.
Because in case of Serializable
readObject reads the required information from the ObjectInputStream
Serialization uses reflection mechanism to get the necessary fields and their corresponding values.
Serializable serializes all the data members (except static and transient).
But in case of Externalizable
No reflection mechanism used.
User doesn't serializes all data members.That's why to fetch values of the members which are not externalized public no arg constructor is required.

How to serialize a non-serializable in Java?

How can I serialize an object that does not implement Serializable? I cannot mark it Serializable because the class is from a 3rd party library.
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. :-)
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.
Alternatively, contact the developer of the non-serializable class and tell him to fix it. :-)
You can use Kryo. It works on non serialized classes but classes needs registered aforehand.
If your class already implements the Serializable interface (required for serializing), all you must do is to declare the field you don't want to serialize with transient:
public transient String description;
If the class is not final, you can make your own class that extends it and implements Serializable. There are lots of other ways to serialize besides Java's built-in mechanism though.

Categories