Java Forum / General / January 2008
serialisation panic
Roedy Green - 11 Jan 2008 16:19 GMT I just woke up with some panicky thoughts about serialisation. Some people dream about women; I dream about Java.
1. If a class does not have a no-arg constructor, how is it possible for serialisation to reconstitute the object?
2. IIRC constructor initialisation does not happen but what about STATIC fields? Do they get initialised? If so, how? Does it call the <clinit> static-initialiser method directly?
3. how does initialisation set the private fields of an object?
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Thomas Fritsch - 11 Jan 2008 16:33 GMT Roedy Green schrieb:
> I just woke up with some panicky thoughts about serialisation. Some > people dream about women; I dream about Java. Poor man ;-)
> 1. If a class does not have a no-arg constructor, how is it possible > for serialisation to reconstitute the object? It is not. See the API doc of Serializable: <quote> During deserialization, the fields of non-serializable classes will be initialized using the public or protected no-arg constructor of the class. A no-arg constructor must be accessible to the subclass that is serializable. </quote>
> 2. IIRC constructor initialisation does not happen but what about > STATIC fields? Do they get initialised? If so, how? Does it call > the <clinit> static-initialiser method directly? I would assume so, since <clinit> is called at class-load-time.
> 3. how does initialisation set the private fields of an object? I guess it does so by some JNI code in Sun's DLLs. (Remember, JNI has the power to set any fields, even the private and final ones.)
 Signature Thomas
Zig - 11 Jan 2008 17:09 GMT > Roedy Green schrieb: >> I just woke up with some panicky thoughts about serialisation. Some [quoted text clipped - 9 lines] > serializable. > </quote> True for a class that is non-serializable. Though I think Roedy's question was about how Serialization does it under the hood for serializable classes?
For those, I assume Serialization is using the JNI function AllocObject:
<quote> jobject AllocObject(JNIEnv *env, jclass clazz);
Allocates a new Java object without invoking any of the constructors for the object. Returns a reference to the object. </quote>
>> 3. how does initialisation set the private fields of an object? > I guess it does so by some JNI code in Sun's DLLs. (Remember, JNI has > the power to set any fields, even the private and final ones.) Maybe, but Reflection can do the same I think (if wrapped into a AccessController.doPrivileged call).
HTH,
-Zig
Zig - 11 Jan 2008 17:50 GMT >> Roedy Green schrieb: >>> I just woke up with some panicky thoughts about serialisation. Some [quoted text clipped - 22 lines] > the object. Returns a reference to the object. > </quote> Actually, I had to look this up.
From java.io.ObjectStreamClass.newInstance()
Creates a new instance of the represented class. If the class is externalizable, invokes its public no-arg constructor; otherwise, if the class is serializable, invokes the no-arg constructor of the first non-serializable superclass. Throws UnsupportedOperationException if this class descriptor is not associated with a class, if the associated class is non-serializable or if the appropriate no-arg constructor is inaccessible/unavailable.
HTH,
Thomas Fritsch - 11 Jan 2008 18:04 GMT >> Roedy Green schrieb: >> [quoted text clipped - 12 lines] > question was about how Serialization does it under the hood for > serializable classes? Oops, you're right. I confused non-serializable with serializable.
> For those, I assume Serialization is using the JNI function AllocObject: > [quoted text clipped - 4 lines] > for the object. Returns a reference to the object. > </quote> Sounds very reasonable to me. Actually for classes like Boolean (implements Serializable, but has no no-arg-constructor) I see no other way for (de)serialization than JNI-AllocObject.
 Signature Thomas
Mike Schilling - 11 Jan 2008 19:23 GMT >>> Roedy Green schrieb: >>> [quoted text clipped - 28 lines] > (implements Serializable, but has no no-arg-constructor) I see no > other way for (de)serialization than JNI-AllocObject. Can I quibble here? (De)Serialization is one of the facilities in Java that require native methods. (Another is synchronization via wait()/notify()). That is, a JVM implementation must implement a way of creating the object that doesn't involve calling a constructor immediately thereafter, and make this mechanism available to readObject(). It's possible that this is the JNI function AllocObject. It's also possible that the two both call some lower-level function. A third possibility is that the implementations are wholly unrelated.
Roedy Green - 11 Jan 2008 17:32 GMT On Fri, 11 Jan 2008 16:33:09 GMT, Thomas Fritsch <i.dont.like.spam@invalid.com> wrote, quoted or indirectly quoted someone who said :
>> 1. If a class does not have a no-arg constructor, how is it possible >> for serialisation to reconstitute the object? [quoted text clipped - 5 lines] >serializable. ></quote> But what about a serialisable class without a no-arg constructor?
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Roedy Green - 11 Jan 2008 19:34 GMT On Fri, 11 Jan 2008 16:33:09 GMT, Thomas Fritsch <i.dont.like.spam@invalid.com> wrote, quoted or indirectly quoted someone who said :
><quote> >During deserialization, the fields of non-serializable classes will be >initialized using the public or protected no-arg constructor of the >class. A no-arg constructor must be accessible to the subclass that is >serializable. ></quote> I am baffled. How could you ever be reconstituting non-serialisable classes?
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Owen Jacobson - 11 Jan 2008 21:59 GMT On Jan 11, 11:34 am, Roedy Green <see_webs...@mindprod.com.invalid> wrote:
> On Fri, 11 Jan 2008 16:33:09 GMT, Thomas Fritsch > <i.dont.like.s...@invalid.com> wrote, quoted or indirectly quoted [quoted text clipped - 9 lines] > I am baffled. How could you ever be reconstituting non-serialisable > classes? Serializable classes can be derived from non-serializable classes. Trivially, java.lang.Object is not serializable...
When reconstituting a serialized blob into an object, the most-derived non-serializable class is reconstituted using Java language mechanisms, which allows it to establish invariants, and then the remaining data is reconstituted by directly manipulating fields on the object.
Yes, Serialization cheats on construction. It's one of the reasons I don't like it very much. :)
-o
Lew - 12 Jan 2008 00:20 GMT > Yes, Serialization cheats on construction. It's one of the reasons I > don't like it very much. :) Joshua Bloch covers this extensively in /Effective Java/. He points out that making a class implement Serializable is a very, very heavy responsibility. You create a public interface to the class that subverts access controls, and lock the (non-transient portion of the) class structure in for eternity if you wish serialized instances to remain compatible.
No one should use Serializable for non-transitory persistence without reading those items in /Effective Java/.
 Signature Lew
j1mb0jay - 12 Jan 2008 00:26 GMT >> Yes, Serialization cheats on construction. It's one of the reasons I >> don't like it very much. :) [quoted text clipped - 8 lines] > No one should use Serializable for non-transitory persistence without > reading those items in /Effective Java/. If i wanted to pass a dataset over a socket how would i do it without making it 'Serializable' ??
j1mb0jay
Lew - 12 Jan 2008 00:36 GMT > If i wanted to pass a dataset over a socket how would i do it without > making it 'Serializable' ?? You can write the values by any number of methods, using ordinary Streams or Sockets. Serializable is for persisting objects (and their reference trees), not data sets.
Some systems use RMI, IIOP or XML to transmit data.
 Signature Lew
j1mb0jay - 12 Jan 2008 00:46 GMT >> If i wanted to pass a dataset over a socket how would i do it without >> making it 'Serializable' ?? [quoted text clipped - 4 lines] > > Some systems use RMI, IIOP or XML to transmit data. I use XML else where in my program, is using a Serializable version of a dataset frowned upon for poor performance ?
j1mb0jay
Lew - 12 Jan 2008 01:45 GMT > I use XML else where in my program, is using a Serializable version of a > dataset frowned upon for poor performance ? It's not the best choice because Serializable has such devastating effects on the maintenance cost of a class. Classes contain behavior as well as data. If all you want to do is persist data, Serializable is waaaay overkill.
Performance is not the issue. Labor is. Flexibility is. Compatibility is.
Performance is far from the most important factor in software.
 Signature Lew
Roedy Green - 12 Jan 2008 06:03 GMT >I use XML else where in my program, is using a Serializable version of a >dataset frowned upon for poor performance ? see http://mindprod.com/jgloss/serialization.html for the downsides.
The biggest problem is fragility. If you change any of your classes, there is a good chance you will never again be able to read your data files. It is ROYAL pain to update the format of serialised files. You need both the old and new formats. Yet both formats belong to a class of the same name.
It is for "transient data" where you can afford to just toss your files and recreate them from scratch or from some sort of formatted files.
The huge advantage is you can write out a giant complicated tree of data with one line of code that does not need to be maintained.
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Zig - 12 Jan 2008 04:42 GMT >> If i wanted to pass a dataset over a socket how would i do it without >> making it 'Serializable' ?? [quoted text clipped - 4 lines] > > Some systems use RMI, IIOP or XML to transmit data. IIRC, to use RMI, one must use Serialization.
From: http://java.sun.com/javase/6/docs/platform/rmi/spec/rmi-protocol4.html
<quote> Call and return data in RMI calls are formatted using the Java Object Serialization protocol </quote>
If I'm not mistaken, when exchanging data through RMI, your values must either be primitive, Serializable, or Remote (to which references will be replaced by Serializable stubs at transmission time).
That said, at the moment I'm a bit to lazy to write an RMI client & server to see what happens when you pass a non-serializable object through...
Lew - 12 Jan 2008 05:37 GMT > IIRC, to use RMI, one must use Serialization. > [quoted text clipped - 13 lines] > server to see what happens when you pass a non-serializable object > through... Good catch, thanks.
It remains that there are many protocols to transmit data or objects. Since the OP's question was about data particularly, not object graphs, Serializable is almost certainly overkill for their needs. They should use a lighter-weight and safer protocol.
 Signature Lew
Roedy Green - 12 Jan 2008 06:00 GMT >You can write the values by any number of methods, using ordinary Streams or >Sockets. Serializable is for persisting objects (and their reference trees), >not data sets. you can use DataOutputStream directly or use it to create packets you send in a raw byte stream.
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Roedy Green - 12 Jan 2008 05:58 GMT On Fri, 11 Jan 2008 13:59:15 -0800 (PST), Owen Jacobson <angrybaldguy@gmail.com> wrote, quoted or indirectly quoted someone who said :
>Yes, Serialization cheats on construction. It's one of the reasons I >don't like it very much. :) Perhaps they should have insisted serialisable classes have a no-arg constructor, possibly private.
Are there circumstances where fields of non-serialisable superclasses don't get saved/restored?
.
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
EJP - 13 Jan 2008 23:28 GMT > Are there circumstances where fields of non-serialisable superclasses > don't get saved/restored? There are no circumstances where they *do* get saved/restored. They're not serializable, so they don't get serialized or deserialized. They get whatever the default contructor and/or the variable initializers put there.
Lew - 14 Jan 2008 00:12 GMT >> Are there circumstances where fields of non-serialisable superclasses >> don't get saved/restored? > > There are no circumstances where they *do* get saved/restored. They're > not serializable, so they don't get serialized or deserialized. They get > whatever the default contructor and/or the variable initializers put there. More precisely, what the no-arg constructor put there.
 Signature Lew
EJP - 14 Jan 2008 23:40 GMT >> whatever the default contructor and/or the variable initializers >> put there. > > More precisely, what the no-arg constructor put there. More precisely still, the state is the same as if you had invoked the no-arg constructor, consisting of what super(), the variable initializers, the instance initialization block {}, and the code in the no-arg constructor put there.
Lew - 15 Jan 2008 02:15 GMT >>> whatever the default contructor and/or the variable initializers put >>> there. [quoted text clipped - 5 lines] > initializers, the instance initialization block {}, and the code in the > no-arg constructor put there. Somewhat redundant, actually. All that happens if you invoke the no-arg constructor, so saying "what the no-arg constructor put there" subsumes the rest.
 Signature Lew
EJP - 28 Jan 2008 07:59 GMT > Somewhat redundant, actually. All that happens if you invoke the no-arg > constructor, so saying "what the no-arg constructor put there" subsumes > the rest. Agreed. I was just making the pedantic point that what the no-args constructor does isn't limited to the code that appears inside it ...
Lew - 12 Jan 2008 00:16 GMT > Roedy Green schrieb: >> I just woke up with some panicky thoughts about serialisation. Some [quoted text clipped - 10 lines] > serializable. > </quote> This says "of non-serializable classes". It doesn't speak to serializable classes.
AFAIK there is no problem deserializing an instance of a class that lacks a no-arg constructor as long as the class implements java.io.Serializable.
>> 2. IIRC constructor initialisation does not happen but what about >> STATIC fields? Do they get initialised? If so, how? Does it call Static fields are initialized when the class is loaded, which will have happened already by the time you're trying to deserialize any instances.
>> the <clinit> static-initialiser method directly? > I would assume so, since <clinit> is called at class-load-time. But this has nothing to do with deserialization, of course.
>> 3. how does initialisation set the private fields of an object? Via the special in-built deserialization mechanism, with possible help from the readObject() and readResolve() methods. The deserializer pulls the values of the private fields from the input stream.
 Signature Lew
Roedy Green - 12 Jan 2008 06:05 GMT >>> the <clinit> static-initialiser method directly? >> I would assume so, since <clinit> is called at class-load-time. > >But this has nothing to do with deserialization, of course. It would if the object coming in the wire has never been seen before. We have the class files on tap, but they have not yet been loaded.
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Lew - 14 Jan 2008 04:31 GMT >>>> the <clinit> static-initialiser method directly? >>> I would assume so, since <clinit> is called at class-load-time. >> But this has nothing to do with deserialization, of course. > > It would if the object coming in the wire has never been seen before. You mean if its class has never been seen before.
> We have the class files on tap, but they have not yet been loaded. OK, not "nothing" to do with serialization, but static fields are not deserialized, they're initialized when the class is loaded, whether because of serialization or for any other reason. In that sense the initialization is not dependent on (de)serialization, which is what I was trying to convey.
The matter of static initialization is orthogonal to serialization, I should have said. Since we are picking nits.
 Signature Lew
Roedy Green - 14 Jan 2008 15:15 GMT >OK, not "nothing" to do with serialization, but static fields are not >deserialized, they're initialized when the class is loaded, whether because of >serialization or for any other reason. In that sense the initialization is >not dependent on (de)serialization, which is what I was trying to convey. Normally class loading happens as a side effect of running constructor or a method. With serialisation reconstitution, you don't run any methods. So some special mechanism is necessary to get the class loaded.
It might call <clinit> or it might use reflection to call some innocuous method of Object.
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Lew - 14 Jan 2008 15:25 GMT >> OK, not "nothing" to do with serialization, but static fields are not >> deserialized, they're initialized when the class is loaded, whether because of [quoted text clipped - 8 lines] > It might call <clinit> or it might use reflection to call some > innocuous method of Object. Regardless of why the class loads, initialization of the static members is a function of class loading, not deserialization.
 Signature Lew
Roedy Green - 14 Jan 2008 16:56 GMT >Regardless of why the class loads, initialization of the static members is a >function of class loading, not deserialization. But then what causes class loading? Perhaps it does a classForName . Does that actually force the load?
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Thomas Fritsch - 14 Jan 2008 18:54 GMT >>Regardless of why the class loads, initialization of the static members is a >>function of class loading, not deserialization. > > But then what causes class loading? Perhaps it does a classForName . > Does that actually force the load? I'd say yes.
During deserialization the ObjectInputStream somehow converts from class names (embedded in the byte-stream) to Class objects, AFAIK in method ObjectInputStream.resolveClass. In this method there is (as you already guessed) indeed a call to Class.forName
 Signature Thomas
Mike Schilling - 14 Jan 2008 16:47 GMT >> OK, not "nothing" to do with serialization, but static fields are >> not [quoted text clipped - 8 lines] > or a method. With serialisation reconstitution, you don't run any > methods. Or there's some hidden method, called during deserialization, which gives you an uninitialized object given the class object,
Object getUninitializedObject(Class clazz)
The class will be initialized when "clazz" is created, e.g. via Class.forName().. No special mechanism required.
> So some special mechanism is necessary to get the class > loaded. > > It might call <clinit> or it might use reflection to call some > innocuous method of Object. Rob - 28 Jan 2008 20:06 GMT I had a good dream about a woman last night. Try it some time.
Rob http://cbmc64.blogspot.com
Lew - 29 Jan 2008 00:23 GMT > I had a good dream about a woman last night. Try it some time [sic]. > > Rob > http://cbmc64.blogspasm.sputum PLONK!
 Signature Lew
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|