Assume I create a class Foo, whose instance variables are instances of different class's. Eg:
class Foo implements Serializable {
BarA barA;
BarB barB;
.
.
BarZ barZ;
}
I understand that when I serialize, I need to all the Bar's to be serializable, else I need to mark them as transient.
But How to know which one's should be marked as transient ? Is this trail and error ?
I understand that when I serialize, I need to all the Bar's to be serializable, else I need to mark them as transient.
Your understanding is incorrect.
Flagging a field as transient causes it to not be stored when an object is serialized. As such, you should only do this for fields whose values are fundamentally impossible to serialize (e.g, a network connection), or fields whose values can be discarded and recreated later (e.g, a cache, or a reference to an application global). Otherwise, the serialized representation of this object will be incomplete.
While it is often the case that a non-serializable object will associated with a transient field, this is not always the case. Understand what "transient" means before you go throwing it around just to make your code run!
You should make sure that all fields that decide the state of your Foo object are serializable, the rest can be transient.
Noone can answer which fields belong to which category but you, the developer.
Even if you are using an external library with no source code and obfuscation, you can write code that using reflection will tell you if it or one of its parent classes and interfaces implements Serializeable.
So there cannot be a situation in which you design code and don't know what you are using.
Related
I have an object with a HashMap field and a few methods that I am trying to serialize. However, at runtime, I am getting a java.io.NotSerializableException.
I was checking to see if HashMaps could be serialized and from what I have read they are so I am not sure what the problem is.
I was just wondering what makes an object be able to be serialized and why would this object that seems to only have fields that can be serialized not be able to as well.
This is defined in the Java platform Spec here:
https://docs.oracle.com/javase/7/docs/platform/serialization/spec/serial-arch.html
The basic rules are these:
"A Serializable class must do the following:
Implement the java.io.Serializable interface
Identify the fields that should be serializable (Use the
serialPersistentFields member to explicitly declare them serializable
or use the transient keyword to denote nonserializable
Have access to the no-arg constructor of its first nonserializable
superclass"
Broadly, in the absence of any indication to the contrary, and field that is not explicitly marked "transient" is a candidate for serialization.
The entire object graph from the target object downwards has to be serializable, or nothing is. That is, every field that references an object (not a primitive) must reference a serializable object.
If I have main class, that is Serializible and create instances of other classes (no inheritance) that are not defined as being serializible, will the state of those classes be also preserved along with the state of the main class, if they are not static? I know that constructors of other objects are bypassed, but what about states? And yes, I did search SO and Google, but came out empty handed, so I hope some nice gent will clear this up quickly for me.
If there is a reference to an object that is not serializable, a NotSerializableException will be thrown.
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.
Source: https://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
You may work around it, as some answers on SO suggest, e.g. Java Serialization with non serializable parts
When I have an immutable parent class A that is NOT final, and another class B extends it(B is mutable), is there any way the immutability of A can be affected because of serialization?
I wrote a small program to serialize an object, changed its state in the program, and then de-serialized it. I got the object back in the form in which it was serialized. So I am wondering is there any way I can alter A's immutability by serializing it?
It depends on exactly what you are asking. If you just want to get a different value back than what you put in, then yes, you can do that through serialization. The serialized data is completely detached from the instance of A that exists in memory. When Java reconstructs an object from the serialized data, it doesn't know or care anything about the original instance of A that was used to create that data. It is simply constructing a data-structure in memory based off of the blueprint provided in the serialized information.
So if you want to modify what you get back when you reconstruct A, you can do so by manually modifying the binary serialized data. Doing so will require a good understanding of Java's serialization format, but it can certainly be done.
Though if you are asking if there is any way to modify the original instance of A through serialization (as in, to somehow get the same object to change in value, without constructing a new instance via deserialization), then the answer is no, you cannot. Serialization simply creates a snapshot of the object's current state. Deserialization creates a new object instance that is completely detached from the source instance. So while you might manually change the value, the new object with the new value will still be immutable once it has been deserialized.
And if you are asking if there a way to serialize an instance of immutable class A and then deserialize the data as something that identifies as an instance of class A but happens to be mutable then the answer is also no. The serialized data specifies what class of object is being represented, but the class definition itself is not serialized. So you could change the specified class such that you serialize an instance of A and then deserialize an instance of mutable class B, but that's not the same as getting back a mutable instance of A.
You can't alter its immutability (the class will still be immutable) but you can alter its values by editing the serialized information.
You can also alter it through reflection, immutable isn't some kind of magic protection, it's just creating a class without mutators to help overal program stability. Although variables should probably be final, that's not even necessary--to be immutable you simply have to always return the same value for all of your methods.
Anyway, if you are going to extend an immutable class, you probably want your extension to be immutable as well--if not chances are you don't really want to extend the class, perhaps you just want to encapsulate it (is there an is-a relationship or a has-a?)
When you serialise an object, that object does not change whether it is immutable or not.
When you de-serialise a new object, its is a reconstruction of the first object based on the information recorded and how you do the de-serialisation.
For example, if you have an immutable class and a field is transient, the de-serialised copy will not have that field set (you made it transient)
I have a class that is serialised. Now I need to add a new variable into the class, with setter and getter methods. This class is sent over wire in RMI.
Without changing the UID, can I add new parameters and getter and setter methods for it? I tried to write an example class that is sent over wire, and did not change the UID, and added new parameters and getter and setter methods for it. On the other end, I tested it and I still got the values properly. I had assumed, if I add new parameters, getter and setter methods, I need to change the UID. Am I wrong?
If you hard-code the SerialVersionUID of a class, (to 1L, usually), store some instances, and then re-define the class, you basically get this behavior (which is more or less common sense):
New fields (present in class definition, not present in the serialized instance) are assigned a default value, which is null for objects, or the same value as an uninitialized field for primitives.
Removed fields (not present in class definition but present in the serialized instance) are simply ignored.
So the general rule of thumb is, if you simply add fields and methods, and don't change any of the existing stuff, AND if you're OK with default values for these new fields, you're generally OK.
Wow, a lot of bad information.
Java serialization is +very+ robust. There are a very well defined set of rules governing backwards compatibility of objects with the same uid and different data. the basic idea is that as long as you don't change the the type of an existing member, you can maintain the same uid without data issues.
that said, your code still needs to be smart about handling classes with potentially missing data. the object may deserialize correctly, but there may not be data in certain fields (e.g. if you added a field to the class and are deserializing an old version of the class). if your code can handle this, than you can probably keep the current uid. if not, then you should probably change it.
in addition to the pre-defined rules, there are advanced usage scenarios where you could even change the type of existing fields and still manage to deserialize the data, but that generally only necessary in extreme situations.
java serialization is very well documented online, you should be able to find all this information in the relevant sun/oracle tutorials/docs.
This only matters if you let Java generate a default UID for your class. It uses the actual members and methods of the class to generate it, thus making it invalid once you change the class structure. If you provide an UID for your class then this only matters if you need to deserialize older versions of your class from a file and such.
Want to define few point to highlight the changes which impacts serialization.
Below you will find the link to Oracle Java Docs for more details.
Incompatible Changes
Incompatible changes to classes are those changes for which the guarantee of interoperability cannot be maintained. The incompatible changes that may occur while evolving a class are:
Deleting fields
Moving classes up or down the hierarchy
Changing a nonstatic field to static or a nontransient field to transient
Changing the declared type of a primitive field
Changing the writeObject or readObject method so that it no longer writes or reads the default field data or changing it so that it attempts to write it or read it when the previous version did not.
Changing a class from Serializable to Externalizable or vice versa.
Changing a class from a non-enum type to an enum type or vice versa.
Removing either Serializable or Externalizable.
Adding the writeReplace or readResolve method to a class, if the behavior would produce an object that is incompatible with any older version of the class.
Link from where the above information is taken
http://docs.oracle.com/javase/7/docs/platform/serialization/spec/version.html#6678
What happens if i'll try to serialize an attribute which is static?
thanks
From this article:
Tip 1: Handling Static Variables
Java classes often hold some
globally relevant value in a static
class variable. We won't enter into
the long history of the debate over
the propriety of global variables -
let's just say that programmers
continue to find them useful and the
alternatives suggested by purists
aren't always practical.
For static variables that are
initialized when declared,
serialization doesn't present any
special problems. The first time the
class is used, the variable in
question will be set to the correct
value.
Some statics can't be initialized this
way. They may, for instance, be set by
a human during the running time of the
program. Let's say we have a static
variable that turns on debugging
output in a class. This variable can
be set on a server by sending it some
message, perhaps from a monitor
program. We'll also imagine that when
the server gets this message, the
operator wants debugging turned on in
all subsequent uses of the class in
the clients that are connected to that
server.
The programmer is now faced with a
difficulty. When the class in question
arrives at the client, the static
variable's value doesn't come with it.
However, it contains the default
static state that's set when the
class's no-argument constructor is
called by writeObject(). How can the
client programs receive the new
correct value?
The programmer could create another
message type and transmit that to the
client; however, this requires a
proliferation of message types,
marring the simplicity that the use of
serialization can achieve in
messaging. The solution we've come up
with is for the class that needs the
static transmitted to include a
"static transporter" inner class. This
class knows about all the static
variables in its outer class that must
be set. It contains a member variable
for each static variable that must be
serialized. StaticTransporter copies
the statics into its member variables
in the writeObject() method of the
class. The readObject() method
"unwraps" this bundle and transmits
the server's settings for the static
variables to the client. Since it's an
inner class, it'll be able to write to
the outer class's static variables,
regardless of the level of privacy
with which they were declared.
And from another article:
Static or transient data
However, this "ease" is not true in
all cases. As we shall see,
serialization is not so easily applied
to classes with static or transient
data members. Only data associated
with a specific instance of a class is
serialized, therefore static data,
that is, data associated with a class
as opposed to an instance, is not
serialized automatically. To serialize
data stored in a static variable one
must provide class-specific
serialization.
Similarly, some classes may define
data members to use as scratch
variables. Serializing these data
members may be unnecessary. Some
examples of transient data include
runtime statistics or hash table
mapping references. These data should
be marked with the transient modifier
to avoid serialization. Transient, by
definition, is used to designate data
members that the programmer does not
want or need to be serialized. See
Java in a Nutshell, page 174: mouse
position, preferred size, file handles
(machine specific (native code)).
When writing code if something is
declared transient, then this triggers
(to programmer) necessity of the
posibility of special code for
serialization later.
To serialize an object, you create
some sort of OutputStream object and
then wrap it inside an
ObjectOutputStream object. At this
point you only need to call
writeObject() and your object is
magically serialized and sent to the
OutputStream. To reverse the process,
you wrap an InputStream inside an
ObjectInputStream and call
readObject(). What comes back is, as
usual, a handle to an upcast Object,
so you must downcast to set things
straight. If you need to dynamically
query the type of the object, you can
use the getClass method. Specifically
dk.getClass.getName() returns the name
of the class that dk is an instance
of. I.e., this asks the object for the
name of its corresponding class
object. (Hmmm, True, but what about
syntax? I still need to know what it
is to declare it...too bad) (C++ can
do this in one operation (dynamic_cast
(gives null if wrong type)), java can
use instanceof operator to check if it
is what I think (see Core Java, Ch5
Inheritence, Casting section)
Yes, we can defnitely serialise the static variable, but we wont be able to get any purpose of serialisation on the static variables.
Why because the Static variables are not bounded to any objects in scope.
We serialize objects to store them so they can retrieved later for any use.
Only the Transient varibles you cant make them to get serialised.
You can serialize the value of a static variable / attribute. But strictly speaking, you don't serialize a variable or attribute in its own right, whether it is class level, instance level, or local to a method.
Normally the instance level attributes of an object are serialized as part of the parent object; i.e. the object that they are attributes of. If you translate that to class level attributes, then the notional parent is the class. While there is a runtime object that denotes this class (i.e. the java.lang.Class returned by this.getClass()), this object is not serializable. So from that perspective, a class level (static) attribute is not serializable.