Does changing the class name affect Java Deserialization? - java

I am making a modification and a separate application that allows replays to be saved for a certain game.
What I have to serialize and deserialize is an 2 arrays of class ContO, arrays of class Plane, Trackers, and a class Medium, and that is no problem.
To extend this functionality, I decide to reconstruct it in the separate application so that it supports 2 versions of said game. The way I plan to do this is to use abstract classes named Medium, ContO, Plane, and Trackers, and the classes that will extend those will be named things like MediumVersion1 and MediumVersion2, ContOVersion1, and so on.
In the original game files the class is named ContO, Plane, Trackers, and Medium for both versions, and what I wonder is: by changing the name of the class to reflect the version of the file that will be deserialized, will it effect the deserialization process?
For example, I serialize the class as the name of ContO in the original game files, but deserialize it under a new class name named ContOVersion1, but contains the exact same variables.

I just tried this and the answer is you cannot change the class name. You will end up with a ClassCastException when you try to cast the object you get back from ObjectInputStream.readObject() into your new class with a different name. This is the case even if you keep the same serialVersionUID on both classes.

You can definitely not do this.
The original class and package names are encoded along with the data, and the incoming object is constructed as that class, so, to avoid a class cast exception, what you cast it to must be identical, as must many other aspects of the class - but not all of them. See the Object Versioning chapter of the Object Serialization Specification for more information.

Related

Read previously exported object with a non primitive class associated

I have exported an ArrayList of instances of class defined by myself, and I need to read in another project. I don't intend to use the methods of that class in particular, only to use its atributes.
I could transform those atribuites into ArrayList of primitive objects, that I could read afterwards without the need of having that class implemented again in that project, but I'm specifically asked not to do so. Is there a way to get only the atributes of such class?

Easy way to copy between simple child classes

I have an abstract super class with 40 attributes. I also have 2 subclasses that basically extend the super class. Now I want to convert one child class with another.
public abstract class ParentClass{
// ... many attributes
}
public ChildClassA extends ParentClass{}
public ChildClassB extends ParentClass{}
A simple class cast like this is not working and throws ClassCastException:
public ChildClassA to(){
return (ChildClassA) ((ParentClass) this);
}
I could manually write a copy constructor but its tedious work.
Another approach is to serialize and convert. For example using XML or JSON. But that is used for cloning a class and again deserializing would throw class cast exception.
Is there are any other better ways?
EDIT:
Since people have asked for design decision:
I have 2 tables of identical columns. One table has data and the other one doesn't. I have to retrieve rows from original table -> do processing -> put back in second table.
So to minimize code complexity I have super class entity (JPA) which has all the fields (more than 40 fields, annotated with`) and have 2 subclasses extending from it (because I can only have 1 #Table annotation per class).
Now to do processing I need to retrieve data from original table to original sub class. Create a new second subclass and copy values from original to new. Do processing. Persist 2nd entity onto 2nd table.
I would question the design decision of extending the base class with subclasses that don't add anything, especially since they have to be converted from one to another. You could use one class instead, but add an enum field that differentiates the types from one another. Then the conversion would be simply changing this field to a different value.
However, if you really need them to be different classes and be able to convert from one to another, and you don't want to write tedious code to copy fields manually, you could look up some Java mapping frameworks, like MapStruct.
A simple class cast like this is not working and throws ClassCastException
Sure, that an expected behavior. It's not possible to type cast between two classes like ChildClassA and ChildClassB that are not bound with IS-A relationship, they are siblings, they don't extend each other, and therefore they are not compatible.
I have an abstract super class with 40 attributes.
If the number of properties is unmanageable, that's clearly a code smell. I suspect that some of these 40 properties can be "folded" into several objects, which will make sense in your domain model.
I could manually write a copy constructor but its tedious work.
Since you have 40 properties, I guess primarily concern is to bring the code to the state when you can more easily maintain it rather than amount of typing. And I've given you advice on that point.
And as a tool for conversion, I would rather declare a method like toChildClassB() because it would be more expressive than a constructor call new ChildClassB(childA).

Are instances of Class immutable?

I was wondering whether Class instances are immutable. The declared methods names do not suggest that the instance state is changed when they are invoked, but I found no explicit guarantee on the javadoc.
Scenario: I need to store unique class names in a Set. Ideally, I would like to populate the set with Class instances to avoid unnecessary calls to Class.forName() when I need to access the classe via reflection. However, it preferable to use immutable objects as keys of sets. Hence I was wondering if I could use Class instances right away.
First, The generics part Class<?> really doesn't matter here. Sure, no raw types, so Class<?> is better than Class, but for your question, the wildcard doesn't matter.
So in essence, you are asking whether Class objects are immutable. And for all practical purposes, they are.
Class objects come into existence when a class loader loads a class, and they stay put unless the whole class loader is unloaded, and everything it loaded with it.
Which can't happen when such class objects are still used in a map somewhere.
On the other hand: Class.forName() shouldn't be too expensive for classes already loaded. And when things such as serialization come into play, people suggest to go with String instead of Class objects for example (see here).
One has to distinguish between the immutable identity of a class object, and the actual "code" belonging to the class. That code can be changed at runtime (by instrumentation, think hot swap of code). But the class name, and its each code, and equals() equality should not be affected by that. Because the "identity" stays the same.
Final note: as the interesting comments below lay out, there are certain ways to alter Class objects to a certain degree. But all of these activities are definitely "out of the norm". Therefore: theoretically, you might prefer Strings over Class objects, but practically, in "normal" applications, using Class should work fine, too.
As I don’t really agree with other answer I decided to write this one,
Classes are not immutable, but they are unique - only one instance of Class object can exist for one class.
BUT class it not defined by its name, as classes might be from different class loaders, and different class loaders might have classes with same names - but that will be different classes, you would get ClassCastException if you would pass some object between code handled by 2 different class loaders if that object type would exist in both of them (as separate one, not inherited).
Class instances can be still safely used in Set, as they use default implementation of hashset/equals so only same instances of Class will be considered equals.
But to decide if you should use String or Class you need to know how exactly your app is supposed to work, as like I said, multiple classes with same name can exist between different class loaders.
And by just storing class name you can’t be sure that Class.forName will return same instance as expected it might even load some other class with same name from current class loader instead of using expected one.

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

Copy of the internal data structure of a class

Out of curiosity, I'd like to know if any class exists in Java with a method that returns a copy of its data structure. I ask because in class the teacher said a method like this breaks privacy, but I think that getting a copy of the structure is useful if you want to rearrange the structure. I'd like an example. Thanks.
I'm not entirely sure what you mean by the "data structure" of a class, but assuming you mean the members it contains, what you're looking for is reflection.
Try this tutorial.
Maybe you are missing the point: If you build a class which encapsulates some kind of internal data then you should NOT add a method which returns the internal data structure, but only the data that is encapsulated.
(Which is kind of the idea of encapsulation)
There should not be any need to "rearrange" your internal representation from the outside - because it is supposed to be internal and thus transparent in its use. (Meaning: You should not even be able to say what kind of data structure is used)
If you serialize it, any object (that is serializable) will happily prints its internal structure to a binary stream. And yes, this breaks encapsulation.
And yes, no one stops you from going to change the binary output and read it in again to create an altered object.
NB: there are more strange issues regarding serialization. For example, when deserializing objects new objects are created without their constructor ever being called. Et cetera. Serialization of objects is the maybe least object-oriented thing one can do with objects.
You're mixing up some concepts here.
Classes really are "data structures + methods", so in general you'd need a class to represent your class. Hey, a nice custom-built one would be the class your data is already in. You may be thinking of a class as a collection of simple fields, but this is not always the case.
As others have mentioned, you can extract the data via reflection, e.g.
public Map<String,Object> fields() {
Map output=new hashMap<String,Object>();
for (Field f:getClass().getFields())
{
try{
output.put(f.getName(), f.get(this));
}
catch(... //IllegalArgument, IllegalAccess.. {... }
}
return output;
}
You can get into encapsulation issues here, in general the class should provide the data that you need to see from it, I tend to use things like this only for debugging.
I'm not sure what you mean by "rearrange the structure". The class generally represents the structure of the data. If there's a transformation you want to accomplish, it probably belongs in a class method, e.g. are you thinking of something like a co-ordinates class that can provide a transformed version of itself into polar co-ordinates?
A simple way to see the internal representation of an object is to serialise it using XStream. This will generate an XML representation of the class and its components (and so on).
Does this break encapsulation ? Yes - in the sense that you're able to inspect the internal structure of the class. You can take that XML, change it, and provided that it matches the .class structure that it came from, deserialise it back into a .class instance.

Categories

Resources