Final field & custom serialized format

I

Ian Pilcher

I have a class which has a single field:

private final File nameFile;

When serializing it, I want to save it as a String, rather than a File.
This will allow me to better check for platform incompatibilities during
deserialization.

I can serialize it like so:

private transient final File nameFile;

private void writeObject(ObjectOutputStream out) throws IOException
{
out.defaultWriteObject();
out.writeObject(nameFile.getPath());
}

A straightforward approach to deserialization won't work, however, for
the obvious reason that I won't be able to set nameFile to the File I
construct from my deserialized String.

I can't be the first person to run into this. What have others done in
this situation?

Thanks!
 
I

Ian Pilcher

Ian said:
A straightforward approach to deserialization won't work, however, for
the obvious reason that I won't be able to set nameFile to the File I
construct from my deserialized String.

Talking to myself again. One answer seems to be the use of writeReplace
and readResolve, although they come with a lot of caveats.

(Can anyone think of a reason why readResolve should have an access
modifier other than private?)
 
C

Chris Uppal

Ian said:
I have a class which has a single field:

private final File nameFile;

When serializing it, I want to save it as a String, ...

Perhaps a simple solution would be adequate for you

class XXX
{
private final String fileName;
private transient File namedFile;
//...
}

and rebuild namedFile lazily, or in a custom de-serialisation step, according
to your taste.

Or -- even simpler -- don't make namedFile final. After all, your design calls
for changing it !

-- chris
 
C

Chris Uppal

Ian said:
(Can anyone think of a reason why readResolve should have an access
modifier other than private?)

In case a subclass wants to say:
if (...)
return super.readResolve();
perhaps ? Or so that you can write tests for your objects' implementations of
the serialisation protocol independently of the complexities of the real
serialisation code ?

-- chris
 
T

tom fredriksen

Ian said:
I can't be the first person to run into this. What have others done in
this situation?

You could try the library xstream, which de-/serialises from/into xml.
The result would be a bit larger than pure a string or binary version,
but it would be very portable and for-/backwards compatible.

/tom
 
T

Thomas Hawtin

Ian said:
Talking to myself again. One answer seems to be the use of writeReplace
and readResolve, although they come with a lot of caveats.

That seems to be the answer from the JMM list.

http://www.cs.umd.edu/~pugh/java/memoryModel/archive/1636.html
(Can anyone think of a reason why readResolve should have an access
modifier other than private?)

pre-1.5 type-safe enums. If you subclass for certain constants, then you
probably don't want to repeat the readResolve method. Much the same goes
for anywhere where the base class is peers with a fixed set of
subclasses. I suppose where creation is done through a static creation
method.

If you are coding for both J2ME and J2SE, then you can't put
serialisation code in J2ME classes. Subclassing every class is not on.
What you can do is insert serialisation base classes on different
sourcepaths for J2ME and J2SE.

Tom Hawtin
 
I

Ian Pilcher

Chris said:
Perhaps a simple solution would be adequate for you

class XXX
{
private final String fileName;
private transient File namedFile;
//...
}

Yeah. Actually playing with writeReplace and readResolve for a while, I
slapped myself and did the following:

private final File nameFile;

private void writeObject(ObjectOutputStream out) throws IOException
{
out.defaultWriteObject();
out.writeObject(nameFile.getPath());
}

private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
String savedPath = (String)in.readObject();

if (!savedPath.equals(nameFile.getPath()) ||
nameFile.getParent() != null)
{
throw new InvalidObjectException(savedPath +
": not compatible with this platform");
}
}

nameFile contains a single element of a pathname, either a "prefix" or a
name. It is properly final, since a single element is immutable. I use
a File, rather than a String, so that I can compare element names and
let the File class worry about the rules of the platform on which I'm
running.

By saving it's original name, I can check that the File serialization/
deserialization doesn't change it's name (\ --> / for example). I also
check that the name doesn't contain anything that's interpreted as a
directory separator on the current platform. Linux allows backslashes
in file names, for example.
 
R

Roedy Green

A straightforward approach to deserialization won't work, however, for
the obvious reason that I won't be able to set nameFile to the File I
construct from my deserialized String.

It is not obvious why.
 
P

P.Hill

Ian said:
Chris said:
Perhaps a simple solution would be adequate for you

class XXX
{
private final String fileName;
private transient File namedFile;
//...
}


Yeah. Actually playing with writeReplace and readResolve for a while, I [...]
slapped myself and did the following: [...]
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
String savedPath = (String)in.readObject();

if (!savedPath.equals(nameFile.getPath()) ||
nameFile.getParent() != null)
{

Hmm, nameFile is null at this point is it not? Thus
I'm not sure this is a general solution. You weren't reading
from a serialization from before changing the definition to
transient where you?

But if you find you miss created something and you could recover
by creating some new version of an XXX, you can create a new class XXX
by using a private constructor within readObject().

HTH,
-Paul
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,835
Latest member
lila30

Latest Threads

Top