Can a transient field in a class be obtained using reflection? (using getDeclaredField(..))
Yes, It is a normal field. You can check whether it is transient by:
Modifier.isTransient(field.getModifiers());
transient:
A keyword in the Java programming language that indicates that a field is not part of the serialized form of an object. When an object is serialized, the values of its transient fields are not included in the serial representation, while the values of its non-transient fields are included.
So no logical reason for it not to be accessible by reflection. It's the value of the field that is ignored (sometimes), not the field itself.
(btw, what hindered you from just trying to call getDeclaredField("yourTransientField")?)
transient indicates that the field will not be serialized. The field is still declared by the class, so it is fair game for reflection.
Among all the objects that needs to be serialized there are those one that need not to be serialized. That's why this objects are marked with the keyword transient.
transient fields have nothing to do with reflection. The keyword only signals that a field should be skipped during Java serialization process. So reflection can access transient fields just like any other fields.
Related
I faced this question in an interview. Please help me to find the answer. The question was Can a transient variable be serialized in any way?
static and transient fields are not serialized by default.
However they can be serialized if
the same object is accessible via a serialized field.
the object is serialized in a readObject/writeObject or readExternalizable/writeExternalizable.
you are using a different serialization library with different rules (I don't know any which serializes static fields, though I have written such a library by mistake once)
Usually a field is made transient to mean it shouldn't be serialized, though sometimes it might be because
the type is not Serializable
you don't want to use the default Serialization.
Recently in an interview I was also asked this question and here what I answered
Yes, transient member can be serialized. We need to do following to acheive same:
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
serialize the individual properties of your non-serializable 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-serializable object.
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
I'm analyzing Java SE 7 project by SonarQube version 5.1.
Then, I faced squid:S1948 on below code.
Fields in a "Serializable" class should either be transient or serializable
Fields in a Serializable class must themselves be either Serializable or transient even if the class is never explicitly serialized or deserialized. That's because under load, most J2EE application frameworks flush objects to disk, and an allegedly Serializable object with non-transient, non-serializable data members could cause program crashes, and open the door to attackers.
enum ShutterSpeed {
private final Rational value; // Make "value" transient or serializable.
...
}
I think that any enum fields won't be serialized in J2SE 5.0 (Serialization of Enum Constants)
Is this a false-positive?
Whole code and issue are here.
It is actually a false-positive. The Serialization of Enum Constants (which you've provided a link to) says that:
Enum constants are serialized differently than ordinary serializable
or externalizable objects. The serialized form of an enum constant
consists solely of its name; field values of the constant are not
present in the form.
As I see it, it doesn't make sense to mark Enum's field values as transient or make them implement Serializable, since they'll never get serialized, no matter if they're marked as transient or implement Serializable.
If that analyzing tool forces you to do one of these two things, then you'll be writing useless code. If I were you, I'd try to disable that warning for enums.
As said, it's a false positive, so you can suppress the warning:
#SuppressWarnings("squid:S1948")
I would simply mark the field as transient.
I need to pass java.lang.reflect.Field from one process to another using RMI, but Field does not implement Serializable interface. how can I overcome this problem?
It doesn't make sense to pass a Field via RMI. A Field instance is really a dependent object of a java.lang.Class instance, and Class objects are not transmissible either. (And the reason that a Class is not transmissible is that it would present all sorts of nasty type checking problems ... considering that a Class instance actually denotes a reference type.)
You will need to declare the relevant Field field as transient. If you want to transmit the Field information, you are probably going to need to pass it in the form of a field name / class name, and then reconstruct the Field at the other end in a custom readObject method.
If I have an instance of a class that I store in a session I need to make it serializable. This class has a static variable, will this be serialized in every instance stored?
The static variable is a reference to a cache containing a lot of data in the background. Will all of this data be serialized? If so, it seems preferable to make this variable transient and re-fetch the cache instance each time the instance is restored. Maybe not store the cache instance at all in the class.
Will the constructor execute when a class is restored from a serialized state? if not is there any other method I can use to re-instate a transient variable?
This class has a static variable, will
this be serialized in every instance
stored?
No. According to the Java Object Serialization Specificaiton: "Default serializable fields of a class are defined to be the non-transient and non-static fields."
Will the constructor execute when a class is restored from a serialized state?
No. Deserialization bypasses constructors (unless you have a non-serializable superclass).
if not is there any other method I can use to re-instate a transient variable?
You can use the readObject() method for that, as described in the Serializable API doc.
static and transient fields are not serialized. No, the constructor is not called. For more details, please check this out: http://java.sun.com/developer/technicalArticles/ALT/serialization/