Java:Immutability and serialization - java

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)

Related

Does Java have a concept of reference ownership or noncopyable classes?

I would like to have some guarantee that instances of some particular class Content is only accessed by its "owner", and if another object wants the same Content it needs to take a deep copy. Coming from C++ I would achieve that using a unique_ptr, is there anything similar in Java?
Currently I am resolving this by just keeping the Content private everywhere I keep one and paying attention to creating a new Content (the constructor implements the deep copy mechanism) on a getContent. But I have no means of enforcing possible other users of the Content class to follow the same pattern, it's easy to forget. It would be nicer if it could take care of itself somehow, like not being copyable.
I realize that it goes somewhat against the spirit of the language, but in some cases I think it's justified. For example, if Content represents some stream of data that is modified even by reading it. I thought, if not in the core language, maybe there is some #interface for compile-time checking or a way of creating one?
Edit: The idea is that the owner can modify the object freely, before or after taking copies, and if someone takes a deep copy, they can modify theirs (not affecting the original), so making the Content immutable is a bit too harsh (unless I'm misunderstanding what that implies).
There are a couple of common strategies here:
Privacy with defensive copying
In this strategy, you'd have the owner have a private reference to the content, and if it's appropriate for it to give out copies of that content, to do so via a defensive copy:
class Owner {
private Content content;
// ...unnecessary detail omitted...
public Content getContent() {
return new Content(this.content);
}
}
The Cloneable interface can sometimes be useful here.
Immutable objects
The other common strategy is to use immutable objects (e.g., ensure that Content, once instantiated, cannot be modified). Then you don't care who has a reference to the content, since they cannot change it.
No there isn't.
Once you have established a reference to an object, there's absolutely nothing you can do to stop someone form assigning another reference to that object via that established reference.
Java programmers get round this by making objects immutable (see java.lang.String). Then you ought not give two hoots about who else is referring to a particular instance.
You can declare the class Content as Immutable by doing this:
Don't provide "setter" methods — methods that modify fields or objects referred to by fields.
Make all fields final and private.
Don't allow subclasses to override methods. The simplest way to do this is to declare the class as final.
If the instance fields include references to mutable objects, don't allow those objects to be changed
Here is a java official doc: https://docs.oracle.com/javase/tutorial/essential/concurrency/imstrat.html
Java does not have something like that. There are some language elements that can help with such requirements:
Enums that have only one constant; to be used as "built-in" singletons
Methods in Collections to create immutable copies of collections
And of course, you can make all fields in your class final; so they get initialized only during construction time; to prevent later changes
But as Java is also missing a const concept, you can partially work around such things. Like in:
class Foo {
private final List<Bar> bars = new ArrayList<>();
doesn't mean that instances of Foo will be immutable - as you still can add/remove elements to that list owned by Foo.
Similar; given
List<Foo> root = ...
List<Foo> immutableCopy = Collections.unmodifiableList(root);
one can still change that immutableCopy ... by messing up root.

Is determining what is transient a trial and error?

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.

Java serialization: static variables not serializable: workaround

Ok, so this question is mostly just related to: is there a better way to do this?
I have a phonebook application, and you can add users to it, delete them, and such, with each person being assigned a distinct ID#. A Person class stores lastIDused as a static class variable. The phonebook class has a vector of Persons.
My workaround thought is this: create a new non-static variable for the Person class, and upon serializing/saving, for the 1st element in the vector only, store the static variable's data into this new variable. Then, when de-serializing, re-set the static variable using the 1st Person's such-variable.
Going back to my original question: is there a better/more-formal/proper way to do this?
A better solution (IMO) would be to make lastIdUsed an instance field of the PhoneBook class. It sounds like you are already serializing an instance of that class ...
FWIW - making lastIdUsed an instance field of Person is just bad object modelling. The field is almost never going to be useful and almost never going to have a valid value. It will only have a valid value in the case of the first serialized Person in a PhoneBook.
First, I would avoid this kind of thing entirely. Static variables aren't serializable for a reason, namely by deserializing something you would invalidate the state of other objects. For example, if your lastUsedId is at 10 and you deserialize an object where it was at 5, it could lead to creating duplicates (6-10).
However, if you are still going to do this, check out the Externalizable interface. It lets you control the serialization and deserialization of an object. Here[1] is a good discussion on it. In the past I've used Externalizable to more tightly control the format of the object being serialized in order to save space. If you really want to, you could serialize a static variable and set it when you deserialize. You could even only set it if it is higher than the value currently in memory. Again, like other commenters I would advise against this approach entirely, but it doesn't hurt to learn this stuff, eh?
[1] What is the difference between Serializable and Externalizable in Java?

Java serialization, UID not changed. Can I add new variables and method to the class?

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

Serialize static attributes in Java

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.

Categories

Resources