Beruflich Dokumente
Kultur Dokumente
The serialization process encodes enough information about the object type within
the byte stream, allowing the original object to be easily recreated upon
deserialization, at a later point in time.
How should I declare fields within my serializable class to prevent them from being
serialized?
Within JDK 1.1, any non-static field declared as transient is not serialized. (Static fields
are not serialized anyway)
Java 2 provides you with another mechanism for specifying which fields need to be
serialized. Your class can declare the static field:
For example:
indicates that only the fields foo and bar must be serialized.
You can turn off this calculation by explicitly defining an SUID in your class. The
SUID must be defined as:
This Is A Myth
Author: Daniel Gredler (http://www.jguru.com/guru/viewbio.jsp?EID=1179237), Jun
16, 2004
This is a prevalent Java serialization myth: that you can speed serialization up by
hard-coding a SUID. The calculated SUID gets cached, so you only incur the
overhead (max 50ms) once. Or maybe more, since they're cached using soft
references, but you get the idea. See
http://www.javaworld.com/javaworld/javaqa/2003-06/02-qa-0627-mythser.html? for
more details.
What is the Stream Unique IDentifier (SUID) that is written out as part of
the serial stream?
Location: http://www.jguru.com/faq/view.jsp?EID=5060
Created: Jan 15, 2000
Author: Govind Seshadri (http://www.jguru.com/guru/viewbio.jsp?EID=14)
The serialization process uses a unique identification value to keep track of the
persisted objects. When a Serializable or Externalizable object is saved, it's fully-
qualified class name and the Stream Unique IDentifier (SUID) of the class is written
out to the stream. The SUID is a unique 64-bit hash, and is obtained by applying the
SHA-1 message digest algorithm to the serialized class, including its name, field
types and method signatures.
This step is important as it prevents the data persisted by one class from being read
by another class with the same name. For any class to be able to read successfully
from an object stream, it is imperative that its SUID matches the SUID of the
serialized data in the stream.
When an object is serialized, its fully qualified class name, as well as the 64-bit
SUID, is written to the stream. Later, when a class attempts to read the serialized
object, it is important that its SUID matches that of the serialized object, as
otherwise an InvalidClassException is thrown.
But therein lies the problem - because, when classes evolve, so do their SUIDs. But
luckily, there is a solution at hand in the form of serialver - a utility provided by the
Java SDK, which allows us to generate the SUID of a Java class file. If the output of
serialver is included within a class file, then that class is now compatible with all it's
persisted objects and can be used to read back the same, even though the class
definition itself may undergo some mutation down the road.
serialver foo.Person
generates:
Now, you can continue to read the foo.Person objects even with future versions of
the class, as long as they have the "old" SUID embedded within them as:
It is probably easier to use a GUI version of serialver, which can be enabled by the
-show option.
serialver x?
Author: Eric Freiborg (http://www.jguru.com/guru/viewbio.jsp?EID=933773), Jul 1,
2002
Is the parameter passed into serialver the class being serialized (x.class or x.java) or is
it the serialized file of that class(x.ser)? Thanks, Eric
Re: serialver x?
Author: Tim Rohaly (http://www.jguru.com/guru/viewbio.jsp?EID=10), Jul 1, 2002
The argument is the class name. serialver uses the standard Java classloader to
search for the class file definition (with file extension .class) in your classpath. The
class file definition can be in a jar file as well, as long as that jar file is in your
classpath. Try this, for example, to print out the SUID for one of the core JDK
classes:
serialver java.lang.String
The Serialization spec does not mandate that the serialVersionUID declared in the
class be any particular value.
If you are creating new class, you can declare it with a serialVersionUID of anything
your like.
As far as I can tell the only reason you would ever want to use serialver is if an earlier
version of the class did not declare a serialVersionUID and you then want to make a
serial-compatible change to that class. Then you would run serialver on the old class
and declare that value in your new class. You then stick with that value until you
make a serial-incompatible change, at which point you can use an number you like
(obviously different from the original number).
The Java Object Serialization Specification specifies which changes are serial-
compatible.
What are the compatible and incompatible changes when dealing with
versioned serialized objects?
Location: http://www.jguru.com/faq/view.jsp?EID=5064
Created: Jan 15, 2000
Author: Govind Seshadri (http://www.jguru.com/guru/viewbio.jsp?EID=14)
A compatible change is one that can be made to a new version of the class, which
still keeps the stream compatible with older versions of the class. Examples of
compatible changes are:
• Addition of new fields or classes does not affect serialization, as any new data
in the stream is simply ignored by older versions. When the instance of an
older version of the class is deserialized, the newly added field will be set to
its default value.
• You can field change access modifiers like private, public, protected or
package as they are not reflected to the serial stream.
• You can change a transient or static field to a non-transient or non-static field,
as it is similar to adding a field.
• You can change the access modifiers for constructors and methods of the
class. For instance a previously private method can now be made public, an
instance method can be changed to static, etc. The only exception is that you
cannot change the default signatures for readObject() and writeObject() if
you are implementing custom serialization. The serialization process looks at
only instance data, and not the methods of a class.
Can't refactor
Author: Alex Chaffee (http://www.jguru.com/guru/viewbio.jsp?EID=3), Aug 15, 2002
In addition to not being able to change the package or name of the class, I believe it is
impossible to change the names of serialized fields. Since "rename" is one of the most
basic and useful refactorings, this is a big problem.
Regarding serialization
Author: Ravishankar CS (http://www.jguru.com/guru/viewbio.jsp?EID=534441), Mar
21, 2002
Hello, you have mentioned that one of the advantages of serialization is that it can be
customized,compressed etc. can u please elaborate on the above 2 points thanking
you, Ravishankar
For example, a serialized object written by Windows can be read by Unix, and vice
verse. This is generally true of all I/O in Java.
Yes. In fact, it is recommended that you buffer all your input and output unless you
have a good reason not to.
...
String myobject = new String("myobject");
FileOutputStream file = new FileOutputStream("myobject.ser");
BufferedOutputStream bout = new BufferedOutputStream(file);
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject(myobject);
out.flush();
...
Likewise, many times it makes sense to compress your output, say if you are writing
many large objects to a file or a socket. You can do this using a ZipOutputStream or
a GZIPOutputStream in place of (or in addition to!) the BufferedOutputStream in
the above example.
When an object is deserialized, its internal state is restored to what it was at the
time of serialization. So if you serialized a good object, you will get a good object
back or an exception will be thrown.
However, there are times when you need to check more than just the state of the
object. Take for example an object that represents a credit card, including cardholder
name, credit card number, and expiration date. If this credit card is deserialized after
its expiration date, then although its state is intact, the card is no longer valid and
can't be used in a purchase transaction. This sort of information may be checked in
the serializable object's readObject() method.
Because serialization saves and restores complete object graphs, you might also
imagine there is a need to validate consistency of the entire graph. This cannot be
done within a single object's readObject() method - it can only be done after all the
objects in the graph are restored.
The validator object must be registered with the stream during the read of the
graph; this is usually done within a readObject() method by invoking the
registerValidation() method on the ObjectInputStream, passing the stream a
reference to the validator object.
Here is a short example which shows the mechanics of validation and demonstrates
that the validation occurs after the object graph has been reconstituted. This simple
example stores objects of type Validate in a collection, and validates upon
deserialization that the collection is homogeneous.
import java.io.*;
import java.util.*;
Vector collection;
Anyway, the validation performed in the sample code gets executed for each and ever
Validate object that gets deserialized. In other words, you can perform the exact
same validation at the end of each readObject() method and the effect is that same.
To prove the point, I've added a few print statements to the original code to show
when and for which objects the validation code is executed. Here is the original code
with the added print statements:
import java.io.*;
import java.util.*;
Vector collection;
I would like to see an example of where the validateObject() method really adds
value. In every situation I've seen, however, the code in the validateObject()
method could be moved to the end of the readObject() an dthe effect would be the
same, but more elegane (IMHO).
main
players=in.readObject();
players.validateObject;
What resources are available to read Java serialized output in C++
programs?
Location: http://www.jguru.com/faq/view.jsp?EID=10361
Created: Jan 31, 2000 Modified: 2000-01-31 09:37:28.249
Author: Tim Rohaly (http://www.jguru.com/guru/viewbio.jsp?EID=10) Question
originally posed by John Zukowski PREMIUM
(http://www.jguru.com/guru/viewbio.jsp?EID=7
Can an application running in a version 1.1.x JVM read an object that was
serialized by an application running in a version 1.2.x JVM?
Location: http://www.jguru.com/faq/view.jsp?EID=13165
Created: Feb 10, 2000 Modified: 2000-05-15 19:46:28.884
Author: Tim Rohaly (http://www.jguru.com/guru/viewbio.jsp?EID=10)
Changes were made to the default serialization stream format between version 1.1.x
and version 1.2.x of the JDK. As a result, if you are writing objects with one version
and reading them with another you may have to take special steps to ensure
compatibility.
There are two distinct forms of the serialization protocol used. These protocol
versions are identified by constants in the ObjectStreamConstants class:
• ObjectStreamConstants.PROTOCOL_VERSION_1
• ObjectStreamConstants.PROTOCOL_VERSION_2
Thus, if both applications use JDK 1.1.7 or higher, the serialization/deserialization will
be successful.
Applications using JDK version 1.2 and higher may override the default serialization
protocol used for writing objects by invoking the useProtocolVersion(int) method
on their ObjectOutputStream, where the integer argument is one of the two
constants shown above. Setting the protocol version to PROTOCOL_VERSION_1
ensures compatibility with all versions of Java when needed.
The Java programming language was designed from the ground up to be compatible
with multiple character sets from multiple languages. This entails using a non-ASCII
character and string representation within the language itself.
Internally, Java stores and manipulates all characters and strings as Unicode.
Externally, in serialization and in bytecode, Java uses the UTF-8 encoding of the
Unicode character set. For each character, UTF-8 encoding is a 1-, 2-, or 3-byte
representation of the corresponding 2-byte Unicode character (ASCII characters are
encoded as 1 byte, non-ASCII characters are encoded as 2 or 3 bytes).
UTF-8 has the property that the ASCII characters 0x20-0x7E encode to UTF-8 1-byte
characters of the same value. Therefore, UTF-8 is 100% compatible with existing
systems which use ASCII encoding. This is one of the main reasons UTF-8 was
chosen for Java's external character representation - it allows complete compatibility
with ASCII as well as allowing for a wide range of international characters.
Instead of specifying the CODE attribute of an <APPLET> tag, you use the OBJECT
attribute, as in:
<APPLET
OBJECT=TheApplet.ser
WIDTH=300
HEIGHT=300
>
</APPLET>
This allows you to preinitialize your applet to some saved state, instead of having to
reinitialize your applet each time it is loaded.
These object streams do allow minimal customization of the protocol. Namely, the
ability to override writeStreamHeader() and readStreamHeader() in subclasses.
This affects only the magic number and version number written at the beginning of
the serialized data, not the internal structure of the data itself. To do any more
customization requires you to write your own stream classes.
This is true even for primitive types written out through the ObjectOutputStream,
because ObjectOutputStream implements its own write() methods to conform to
the serialization protocol.
...
FileOutputStream file = new FileOutputStream("test.ser");
ObjectOutputStream out = new ObjectOutputStream(file);
out.write(65);
out.flush();
out.close();
...
The resulting file, "test.ser", will have a total length of 7 bytes, as follows:
0xACED // ObjectStreamContents.STREAM_MAGIC
0x0005 // ObjectStreamContents.STREAM_VERSION
0x77 // ObjectStreamContents.TC_BLOCKDATA
0x01 // length of data
0x41 // 65 decimal
There is a lot of logic behind the serialization protocol. From the above example, you
see that the protocol writes out an indicator that a block of data follows, then writes
out the length of the data, and finally the data itself. This allows efficient reading of
the data by a stream, and accomodates variable-length data structures. If you really
want to define your own protocol, you will have to write your own input and output
stream classes that that use your own binary format. You will then need to use these
in place of ObjectInputStream and ObjectOutputStream. You will probably want to
implement Externalizable in all your classes as well, so you can control how each
object writes its own state.
This algorithm poses a problem if you send an object, make a change to that object,
then try to send it again; the receiving end will not read the changed object, it will
reconstruct the original object using the object handle.
You can tell the ObjectOutputStream to "forget" about previously serialized objects
by invoking the reset() method. Resetting the stream causes the stream to behave
as if it were just constructed, without any knowledge of what was written to the
stream prior to the reset(). You should use this method only when required,
otherwise you will end up serializing far more data than necessary.
In Java versions prior to 1.3, there is a limit of 64kB on the size of a serialized
String object. This is because ObjectOutputStream delegates String serialization
to an instance of DataOutputStream, which writes out the length of a string as a 16-
bit short, followed by the UTF-8 encoded string. The 64kB limit is due to the
maximum value a short datatype can hold. A UTFDataFormatException will be
thrown if you try to serialize a String greater than 64kB in these versions of the
JDK.
This restriction has been removed by implementation changes in Java 2 SDK versions
1.3 and later. If you attempt to deserialize a String larger than 64kB in a pre-1.3
JVM you will get a StreamCorruptedException.
No.
Comments and alternative answers
There are some Java Security settings that do affect serializaton, however.
Author: Dave Masser-Frye (http://www.jguru.com/guru/viewbio.jsp?EID=939347),
Jul 5, 2002
According to the Object Serialization Specification,
If the subclass of ObjectInputStream is not considered part of the system domain, a
line has to be added to the security policy file to provide to a subclass of
ObjectInputStream permission to call enableResolveObject. The
SerializablePermission to add is "enableSubstitution". AccessControlException is
thrown if the protection domain of the subclass of ObjectStreamClass does not have
permission to "enableSubstitution" by calling enableResolveObject. See the document
JavaTM Security Architecture (JDKTM 1.2) for additional information about the
security model.
There are limits, but it's difficult to quantify most of them. For example, the JVM
stack size affects the graph serialization, since the tree walking is done depth-first,
recursively. (This is called post-order traversal.) Too deep a recursion causes stack
overflow. This limit can kick in for data structures on the order of 1000 deep,
regardless of the size of the objects.
Other, less restrictive limits are that the object handle assigned to each object in a
graph is an int, so there is a (rather large) limit on the number of objects in a
graph. Likewise, the JVM places a limit on the number of members in an class, so
objects have a limit on their size.
I think the only practical limit you are likely to encounter is the stack size. This can
be avoided by customizing serialization with your own structure-specific
readObject() and writeObject() methods.
I got the output by catching a StackOverFlowError. The RMI call looked something
like this:
rmiApp.pocessDoc(Document doc);
The @serial javadoc tag is used to document the meaning and acceptable values of
serialized fields. It appears in a javadoc comment just prior to a field declaration,
and is followed by a free-form field description, which may span more than one line.
In the standard javadoc output, this information is displayed only in the "Serialized
Form" page for that class.
If this serializable field has been added since the initial version of the class, the
@since tag should also be used to help document the version changes in the
serialized form.
I'm having trouble getting Externalizable to work. Can you give a simple
code example?
Location: http://www.jguru.com/faq/view.jsp?EID=32108
Created: Apr 4, 2000 Modified: 2000-04-04 12:07:30.157
Author: Tim Rohaly (http://www.jguru.com/guru/viewbio.jsp?EID=10) Question
originally posed by Rama Turaga
(http://www.jguru.com/guru/viewbio.jsp?EID=30127
The following code defines a simple Externalizable class that provides a main()
method which instantiates an object, writes it to a file, restores it, then verifies that
the restored object contains the same values as the original.
import java.io.*;
import java.util.*;
/**
* This program demonstrates how to write an Externalizable class
*/
public class TestExternal implements Externalizable {
/**
* A no-argument constructor is required for an Externalizable class
*/
public TestExternal() {
this(null);
}
/**
* This method is responsible for saving the
* entire state of the object
*/
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(comment);
//
// You could also just do out.writeObject(collection) below,
// but I prefer to loop over the contents and write them one
// at a time.
//
out.writeInt(collection.size());
Enumeration e = collection.elements();
while (e.hasMoreElements()) {
out.writeObject(e.nextElement());
}
}
/**
* This method is responsible for restoring the
* entire state of the object
*/
public void readExternal(ObjectInput in)
throws ClassNotFoundException, IOException {
//
// What was written in writeExternal() must be read back here.
//
comment = (String) in.readObject();
int size = in.readInt();
collection = new Vector(size);
for (int i=0; i<size; i++) {
collection.addElement(in.readObject());
}
}
/**
* Delegates equality check to the objects stored within
* this instance
*/
public boolean equals(Object o) {
if (o instanceof TestExternal) {
TestExternal other = (TestExternal) o;
if (comment.equals(other.comment) &&
collection.size() == other.collection.size() ) {
for (int i=0; i<collection.size(); i++) {
if
(!collection.elementAt(i).equals(other.collection.elementAt(i)))
return false;
}
return true;
}
}
return false;
}
//
// Write the object to a file
//
ObjectOutputStream out = new ObjectOutputStream(
new
FileOutputStream("testexternal.ser"));
out.writeObject(original);
out.flush();
out.close();
//
// Now read the object back in from the file
//
ObjectInputStream in = new ObjectInputStream(
new
FileInputStream("testexternal.ser"));
TestExternal restored = (TestExternal) in.readObject();
//
// Compare original object with restored object to
// check that they are the same
//
if (restored.equals(original)) {
System.out.println("The original is the same as the
restored");
}
else {
System.out.println("There was a problem with
Externalization:");
System.out.println("\tThe original and the restored aren't
equal");
}
}
}
How can I save an Image object using serialization?
Location: http://www.jguru.com/faq/view.jsp?EID=32308
Created: Apr 4, 2000 Modified: 2000-05-19 18:25:26.775
Author: Tim Rohaly (http://www.jguru.com/guru/viewbio.jsp?EID=10) Question
originally posed by Tim Rohaly PREMIUM
(http://www.jguru.com/guru/viewbio.jsp?EID=10
ImageIcon provides a getImage() method for you to recover the stored Image
object, so you may either use it directly or you may mimic the technique displayed in
the source below to serialize images in your own code.
/**
* Excerpted from the javax.swing.ImageIcon source code
*/
public class ImageIcon implements Icon, Serializable {
/*
*/
int w = getIconWidth();
int h = getIconHeight();
int[] pixels = image != null? new int[w * h] : null;
if (image != null) {
try {
PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h,
pixels, 0, w);
pg.grabPixels();
if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
throw new IOException("failed to load image
contents");
}
}
catch (InterruptedException e) {
throw new IOException("image load interrupted");
}
}
s.writeInt(w);
s.writeInt(h);
s.writeObject(pixels);
}
int w = s.readInt();
int h = s.readInt();
int[] pixels = (int[])(s.readObject());
if (pixels != null) {
Toolkit tk = Toolkit.getDefaultToolkit();
ColorModel cm = ColorModel.getRGBdefault();
image = tk.createImage(new MemoryImageSource(w, h, cm,
pixels, 0, w));
}
}
}
Note that using an integer for each pixel is an extremely inefficient way to save an
image. GIF or JPEG encoded images can easily be 10 times more compact. If size is
a concern, you might want to investigate other image formats. For example, at
http://www.acme.com/ you can find classes that let you write an image out in GIF
format. Alternatively, you can compress your array of integers before writing it to the
stream.
Although it's not obvious, arrays in Java are objects; they have methods you can
invoke (toString(), equals(), etc.) and contain instance variables (length). The
unnamed array superclass also implements Serializable, so all array types can be
serialized directly, without any further work from the programmer, as shown in the
following code example:
// Serialize an int[]
ObjectOutputStream out = new ObjectOutputStream(new
FileOutputStream("test.ser"));
out.writeObject(new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
out.flush();
out.close();
// Deserialize the int[]
ObjectInputStream in = new ObjectInputStream(new
FileInputStream("test.ser"));
int[] array = (int[]) in.readObject();
in.close();
The usual restrictions apply, of course - if you have an array of objects, the contents
of that array must also be serializable in order for the array to be successfully
serialized.
When you serialize an object, the serialization mechanism works by chaining up the
inheritence hierarchy, saving the sate of each Serializable superclass in turn.
When serialization reaches the first non-serializable superclass, the serialization
stops.
When deserializing, the state of this first non-serializable superclass is restored not
from the stream, but by invoking that class' no-argument constructor. If the no-
argument constructor is not adequate for your purposes, you must customize the
serialization of your subclass with writeObject() and readObject() in order to
write out and restore any information from the non-serializable superclass that you
find necessary.
When using object streams over sockets, I have to flush the streams after
each write operation. In fact I even have to flush the output stream soon
after creation. Is there a way out of this?
Location: http://www.jguru.com/faq/view.jsp?EID=35512
Created: Apr 12, 2000 Modified: 2000-04-12 12:47:14.803
Author: Tim Rohaly (http://www.jguru.com/guru/viewbio.jsp?EID=10) Question
originally posed by Viswanathan Kodaganallur
(http://www.jguru.com/guru/viewbio.jsp?EID=35421
It seems you are expecting to be able to read the data on the other end of the
stream immediately after it is written; as you have found out, the only way to ensure
that the data is sent over the socket immediately is to flush the buffer. The
alternatives, setting the buffer size to be very small or turning off buffering entirely,
are not available with socket output streams.
The other problem you mention, having to flush the buffer after creation of the
ObjectOutputStream, is similar. Instantiating an ObjectOutputStream causes the
stream header information to be written to the underlying (buffered) stream. On the
other end, instantiating ObjectInputStream causes this header information to be
read from the stream. If the output stream buffer hasn't been flushed, then the
ObjectInputStream constructor will block until it can read the header information.
Hence, when using buffered I/O, it is usually a good idea to flush the
ObjectOutputStream right after creation. There is no other way to do this.
RMI uses serialization as its basic and only mechanism for sending objects across a
network.
RMI will allow you to pass any object that is serializable according to the serialization
specification. This includes objects that implement Externalizable as well as
objects that implement Serializable.
Note that Externalizable extends Serializable, so anywhere you see the use of
the generic term "serializable" you can assume it refers to objects that implement
either of these interfaces.
In the standard javadoc output, this information is displayed only in the "Serialized
Form" page for that class.
The javadoc documentation for every Swing class contains the warning that
"Serialized objects of this class will not be compatible with future Swing
releases." What exactly does this mean, and how does it affect how I write
my Swing applications?
Location: http://www.jguru.com/faq/view.jsp?EID=38977
Created: Apr 21, 2000 Modified: 2000-04-25 06:11:06.652
Author: Praful Kapadia (http://www.jguru.com/guru/viewbio.jsp?EID=38976)
Question originally posed by Tim Rohaly PREMIUM
(http://www.jguru.com/guru/viewbio.jsp?EID=10
Serializing JavaBeans
Serializing an object is the process of turning its state into a sequence of bytes that
is neither a .java nor a .class file. Why would you want to do such a thing? That
sequence of bytes can be saved as a file on a disk or sent over a network. When a
request is made to restore an object from a file or on the other end of a network
connection, the sequence of bytes is deserialized into its original structure.
For JavaBeans, serialization provides a simple way to save the state of a bean
between one session and another. This is also called component persistence. For
example, suppose the user of a bean changes the values of several properties. If the
bean is serialized to a file and then deserializing the next time the user uses it, the
bean is restored exactly as the user left it.
Sun hadn't yet decided the final format for serialized objects. I suspect when they
do, they'll opt for XML format.
[FAQ Manager Note] Sun has released the specs of the new XML serialization. See
http://java.sun.com/products/jfc/tsc/articles/persistence/index.html for details
See http://www.jguru.com/jguru/faq/view.jsp?EID=20435.
You can subclass this class into one that's Externalizable and define a no-argument
constructor for it. The implement your constructor to call whichever superclass
constructor pleases you. Implement writeExternal() by saving off the fields you're
interested in. Implement readExternal() to read these fields back in and reconfigure
the superclass. In this way, you effectively take over all serialization work; it's as if
the superclass doesn't even implement Serializable.
Serialization is a recursive process. If your object graph is too deep, then you could
overflow the JVM stack. To prevent this, implement readObject() and
writeObject() and use your superior knowledge of the structure of your object
graph to efficiently serialize your objects.
The following piece of code shows you how to do this for the class
java.lang.String:
String s = new String("test");
Class cl = s.getClass();
long uid = ObjectStreamClass.lookup(cl).getSerialVersionUID();
The value of uid will be the same as the value printed out by serialver
java.lang.String.
One way of eliminating the extra instances and some of the unnecessary heap
allocation would be to do something like this:
SerializedForm(int value) {
this.value = value;
}
Object readResolve() throws ObjectStreamException {
if (value == MALE_FORM.value) {
return Gender.MALE;
} else {
return Gender.FEMALE;
}
}
}
}
This also guarantees that in all cases where genderInstance.equals(MALE) is true,
genderInstance == Gender.MALE is also true.
This was a trivial example. I've used this mechanism in other instances where a
great deal of storage or time could be saved by serializing only a shorthand or
mnemonic form of the object - consider the definition of a currency which could be
serialized as only its mnemonic symbol.
1. Speed of reading and writing serialized objects was improved up to 40%. This
also dramatically improves RMI performance.
2. Limit of 64K on the size of strings has been removed. This entailed changes in
the serialization protocol. Older versions of the Java SDK still can't read these
long Strings, and will generate a java.io.StreamCorruptedExceptio if they
encounter this new protocol.
3. More specific information is reported when an exception occurs during
deserialization. This is important for RMI because code movement and
dynamic class loading are particularly hard to debug unless specific error
messages are generated.
The solution is to protect the objects in the graph from modification during the
serialization, or to design your objects such that the graph is consistent even if
individual objects are modified during serialization. This is, in general, a non-trivial
task. Proper use of the transient keyword and customization of serialization
through the use of readObject() and writeObject() will allow you to control
exactly what parts of your graph are serialized.
Not directly. I/O in Java is performed through streams, and encryption is typically
implemented as an algorithm operating on a stream - the input to the stream is clear
text, the output is encrypted.
Although this isn't true encryption, because they can always 'decrypt' the data using
gunzip on the command line, it prevents the data from being viewed in a file editor
directly.
The Java runtime environment has many features that contribute to security and
robustness in a program. For example, the runtime environment enforces access
permissions to private, protected, or "default" members. But when you serialize your
objects, you are in effect removing them from the runtime environment, thereby
exposing them to access that would normally not be allowed - e.g. anyone can come
along and read the contents of a private variables from a serialized object. This is
why it is important to consider security when you are designing your classes for
serialization.
• The first is the obvious step that classes need to be explicitly declared as
implementing Serializable or Externalizable - your class cannot be
serialized without a concious decision on your part to make it so.
• Java provides a transient keyword which prevents a primitive type or object
reference from being written to the stream. You may use this to control which
information is sent out. For example, you may mark a private password field
as transient so that it isn't written out - this prevents someone from coming
along and reading your password directly from a serialized object.
• Serialization is a stream-oriented process, so you may apply any stream-
based encryption to your serialized objects.
• Deserialization can't overwrite existing objects in memory - it can only create
new objects.
• Loading classes for serialized objects is done through the normal class loader
mechanism, therefore is protected by the usual Java security mechanisms.
The above is not a comprehensive list; more information on this subject may be
found at: http://java.sun.com/security/seccodeguide.html and
http://java.sun.com/products/jdk/1.2/docs/guide/serialization/spec/security.doc.html
.
How can I read and write serialized objects to and from a database?
Location: http://www.jguru.com/faq/view.jsp?EID=74403
Created: Jun 13, 2000 Modified: 2000-06-13 12:12:18.258
Author: Simon Brown (http://www.jguru.com/guru/viewbio.jsp?EID=44588)
Question originally posed by edwin abiraham
(http://www.jguru.com/guru/viewbio.jsp?EID=41880
If your RDBMS supports them, you can store serialized objects as BLOBs.
These are JDBC 2.0 features, but take a look at java.sql.Blob, ResultSet and
PreparedStatement for more information.
Alternatively, instead of using standard java serialization you might consider storing
an object in XML using your own (or third-party) serialization scheme. Since the
objects are stored in XML you have the benefit using VARCHAR fields as well.
Base64 Encoding
Author: Stephen Ostermiller
(http://www.jguru.com/guru/viewbio.jsp?EID=576685), Sep 24, 2002
Open source, GPL implementation from com.Ostermiller.util:
http://ostermiller.org/utils/Base64.html
It can encode and decode strings, byte arrays, files, and streams.
Open source, freeware (except military) from Roedy Green's Java Glossary:
http://mindprod.com/jglossbase64.html
http://mindprod.com/products.html#BASE64
Encodes from byte arrays to strings, decodes from strings to byte arrays.
JavaWorld tip with annotated code and nifty graphic that shows how Base64
encoding works (license unknown).
http://www.javaworld.com/javaworld/javatips/jw-javatip36-p2.html
Supports byte array to byte array operations.
The last item is probably the most common problem - it will occur if you write out an
Externalizable object using Java version 1.2 and try to read it in using Java
version 1.1.5 or less. The other reasons might occur if, for example, you transferred
the .ser file to a different computer by FTP and forgot to use binary mode.
Method implementations, whether native or pure Java, are not part of the serialized
state of an object. There is nothing that prevents objects with native methods from
being serialized.
<JAVA-OBJECT-ARCHIVE VERSION="0.1">
<CLASS ID="JPanel" NAME="javax.swing.JPanel"/>
<CLASS ID="JButton" NAME="javax.swing.JButton"/>
<CLASS ID="Test" NAME="Test"/>
<CLASS ID="Rectangle" NAME="java.awt.Rectangle"/>
<CLASS ID="Integer" NAME="java.lang.Integer"/>
<CLASS ID="JTextField" NAME="javax.swing.JTextField"/>
<OBJECT ID="JPanel0" CLASS="JPanel">
<OBJECT METHOD="add">
<OBJECT ID="JButton0" CLASS="JButton">
<OBJECT METHOD="addActionListener">
<OBJECT CLASS="Test"/>
</OBJECT>
<OBJECT PROPERTY="bounds" CLASS="Rectangle">
<OBJECT CLASS="Integer" VALUE="10"/>
<OBJECT CLASS="Integer" VALUE="20"/>
<OBJECT CLASS="Integer" VALUE="100"/>
<OBJECT CLASS="Integer" VALUE="20"/>
</OBJECT>
<OBJECT PROPERTY="text" VALUE="cut"/>
</OBJECT>
</OBJECT>
<OBJECT METHOD="add">
<OBJECT ID="JTextField0" CLASS="JTextField">
<OBJECT PROPERTY="nextFocusableComponent"
IDREF="JButton0"/>
<OBJECT PROPERTY="bounds" CLASS="Rectangle">
<OBJECT CLASS="Integer" VALUE="30"/>
<OBJECT CLASS="Integer" VALUE="50"/>
<OBJECT CLASS="Integer" VALUE="200"/>
<OBJECT CLASS="Integer" VALUE="20"/>
</OBJECT>
</OBJECT>
</OBJECT>
<OBJECT PROPERTY="layout"/>
<OBJECT PROPERTY="bounds" CLASS="Rectangle">
<OBJECT CLASS="Integer" VALUE="0"/>
<OBJECT CLASS="Integer" VALUE="0"/>
<OBJECT CLASS="Integer" VALUE="539"/>
<OBJECT CLASS="Integer" VALUE="366"/>
</OBJECT>
</OBJECT>
</JAVA-OBJECT-ARCHIVE>
The use of XML in this manner is not officially part of the Java language, and a
detailed discussion of this topic is beyond the scope of this FAQ. The article by Philip
Milne and Kathy Walrath provides additional information for the interested reader
[http://java.sun.com/products/jfc/tsc/articles/persistence/].
Both these classes implement Serializable, and have been designed for
serialization. So yes, they can be serialized.
One thing you have to watch out for, though, is that in order to serialize a collection
like Vector or Hashtable, you must also be able to serialize all of the objects
contained in these collections. Otherwise, the collection would not be able to be
completely restored. Your program will throw a NotSerializableException unless
all objects stored in the Vector or Hashtable are also serializable.
One way to solve this is to override the readObject() instance method in the class
which you are serializing and whose variable names have changed.
Suppose that in version 1, the class had instance variables named m_str1 and m_n1
and in version 2, it had m_str2 and m_n2. Then:
ObjectInputStream.GetField gf = in.readFields();
The problem here is that if you call readFields() to determine the version of the
class, you have then read all of the persistent fields for the class and you then
(presumably) have to get the fields using gf.get(). It would instead be nice to be
able to detect the old version without incurring the speed hit when reading the new
version.
The only way that I can think of is to write a version number at the beginning of the
stream using some Version class. Then the hit would only be felt on one (small)
class.
When used in connection with serialization, an object graph is a tree structure rooted
at the object you have written to the ObjectOutputStream. The branches and leaves
of the tree are all the objects which are reachable by following references from the
root object. This structure is maintained by the ObjectOutputStream in order to
ensure that the complete reachable state of the given object is serialized and to
handle cyclic dependencies. The graph is computed on-the-fly, during the
serialization process.
A side-effect of maintaining this graph is that an object which has already been
written to the stream will not be written again - it will be replaced by an object
stream identifier, simply a number used to point at the previously object. To force a
changed object to be written in its entirety, you need to reset() the stream, which
clears the object graph. See http://www.jguru.com/jguru/faq/view.jsp?EID=25970
for more information.
"[A]n object graph is a tree structure" is technically incorrect. A tree structure is like a
real tree, in that the branches never meet up again. However, two Java references
"pointing" at the same object is precisely equivalent to branches of a tree joining up
again.
You can also have branches that loop back to an earlier part of the tree - or "circular
references". These rather odd "trees" are properly called "graphs".
The ObjectStreamClass is used to check if the version of a serialized class (.ser file)
is compatibile with the version of a class in memory/loadable from the CLASSPATH.
See How can I programmatically obtain the serialVersionUID for a class? for an
example of its usage.
It can also be used to get a descriptor for the fields in the stream. See the
Serialization Specification for more information.
Starting with Java 2 Standard Edition, version 1.2, instead of using the transient
keyword to define what fields are serializable within a class, you may create an array
of ObjectStreamField objects to define the serializable fields within the class. This is
demonstrated in How should I declare fields within my serializable class to prevent
them from being serialized?
The difference is that when you load the bean by its bytecode the bean loader
normally create an instance from it by calling the default constructor (no arguments
constructor). If you have a serialized instance the loader creates the instance like it
was when it was serialized and therefore its internal state is recreated (except
transient fields).
Therefore you can provide already customized beans for a particular purpose instead
of letting the bean user do this. So you can provide beans for the different Swing
look and feels which vary in its background color, borders, fonts, etc. Then the bean
user can select for the one he prefers instead of trying settings the bean properties.
See also:
How can I modify a serialized object which is stored in a file if the file
contains a large number of objects?
Location: http://www.jguru.com/faq/view.jsp?EID=114601
Created: Jul 30, 2000 Modified: 2000-07-31 12:16:49.23
Author: Doug Bell (http://www.jguru.com/guru/viewbio.jsp?EID=113602) Question
originally posed by balaji chittu
(http://www.jguru.com/guru/viewbio.jsp?EID=95194
The short answer is that you probably can't without deserializing the objects and
reserializing and rewriting the objects.
The serialized format is truly a stream-oriented protocol and does not support
random access--it is both self-referential and incremental. When an object is written
to the stream, a description of the class and its non-static and non-transient fields
(including any Serializable superclasses and their non-static and non-transient
fields) is also written to the steam. Then the entire object graph of non-transient
fields of Serializable classes is written, which means that non-null object
references to serializable objects are recursively serialized. Throughout this process,
object identity is maintained by adding object handles to a table maintained by both
ObjectOutputStream and ObjectInputStream. When an object previously
encountered in the stream is serialized, only the object handle is written to the
stream. Object handles are used to maintain identity for not only objects, but also
the class descriptions and even the strings used for class and field names.
So even if you had the offset within the stream of the object you want to modify,
without having processed all of the preceeding content it is unlikely that all the data
needed to interpret the serialized data for the object would be present.
How can an applet read a serialized object residing in the same directory?
Location: http://www.jguru.com/faq/view.jsp?EID=118958
Created: Aug 4, 2000 Modified: 2000-08-04 09:31:07.376
Author: Jon Wingfield (http://www.jguru.com/guru/viewbio.jsp?EID=41079)
Question originally posed by amol sinha
(http://www.jguru.com/guru/viewbio.jsp?EID=84027
try {
InputStream is = new URL(getDocumentBase(),
"myClass.ser").openStream();
ObjectInputStream ois = new ObjectInputStream(is);
Object o = ois.readObject();
System.out.println(o);
ois.close();
} catch (ClassNotFoundException cnfe) {
System.out.println(cnfe);
} catch (IOException ioe) {
System.out.println(ioe);
}
A more general mechanism would be to use the static getResourceAsStream(...)
method of ClassLoader. This searches for the resource along the application
classpath and returns an InputStream to the resource. The serialized object file can
now be either on the Web Server or bundled as part of the applet's jar archive. If the
serialized file is not being changed by some other process then it would make sense
to have it in the jar as this reduces the number of requests the applet needs to make
to the server.
It's a good idea to think of deserialization as yet another public constructor. So, if
you have any post-construction activities that you want your object to deal with such
as initialization of transient fields, validation, registering for events, etc. then you
should implement readObject(). Remember to have it call defaultReadObject()
first and then do your thing.
Comments and alternative answers
Where can I find the official documentation of the Sun Java SDK tools?
Location: http://www.jguru.com/faq/view.jsp?EID=138528
Created: Aug 30, 2000 Modified: 2000-08-30 11:20:52.803
Author: John Mitchell (http://www.jguru.com/guru/viewbio.jsp?EID=4)
You can find the official Sun documentation for all of the tools in the Java 2 SDK
including javac, java, javadoc, appletviewer, jar, jdb, javah, javap, extcheck, rmic,
rmiregistry, rmid, serialver, native2ascii, keytool, jarsigner, policytool, tnameserv,
idlj, and unregbean on the Java 2 SDK Tools and Utilities page.
No. Method bodies do not hold any information on the state of an object, so they are
not needed in order to save or restore the state.
Comments and alternative answers
Serialization saves only the state of the object. If some instance variables don't
contribute to the state, there's no sense in spending the extra time and bytes
serializing them. As for how much performance you'll gain, that depends on your
objects. If the instance variables are primitives, you won't save much, but if the
instance variables are object references, the savings can be much greater.
If however the instance variable you declare transient are part of the state of the
object, you will need to reconstruct the transient values upon deserializing. This
requires you to implement private void readObject() and private void
writeObject(). In general, objects which implement readObject() and
writeObject() have better serialization performance because the object streams
don't have to use reflection as much to figure out the detailed structure of the
object. But this is by no means a hard-and-fast rule - it's easy to decrease
performance by an inefficient readObject() or writeObject() method.
The only sure way to find out is to test it with your own objects, within your own
application. Trying to "tune" the performance of your application by setting variables
to be transient is probably not a good thing to do - it would be much better to design
your objects for serialization from the start by understanding, on an object-by-object
basis, what information needs to be serialized and making sure that variables which
don't constitute the state are declared transient.
http://www.jguru.com/jguru/faq/view.jsp?EID=3419
and
http://www.jguru.com/jguru/faq/view.jsp?EID=42504
Is there any way to save the state of an object of a class which does not
implement Serializable or Extenalizable?.
Location: http://www.jguru.com/faq/view.jsp?EID=221619
Created: Oct 3, 2000 Modified: 2000-10-20 11:48:44.577
Author: swarraj kulkarni (http://www.jguru.com/guru/viewbio.jsp?EID=121306)
Question originally posed by poobalan r
(http://www.jguru.com/guru/viewbio.jsp?EID=219451
Yes. You will have to write the value of each and every instance variable into the
persistent storage. If there are 100 variables, you will have to store each of them
individually. If some of the variables are object references, you will have to follow
each reference and save the state of that object as well. You can do that, but it
would be a proprietary solution and each class that wanted to read your object would
also have to know all about your proprietary format.
Comments and alternative answers
As a direct replacement, it also handles all the other aspects of serialization, such
as invoking an objects readObject() and writeObject() methods.
As a bonus, the output is in XML, so you can read what the state is manually.
http://www.csse.monash.edu.au/~bren/JSX
What's the difference between the SUID (Stream Unique IDentifier) and the
private static member serialVersionUID?
Location: http://www.jguru.com/faq/view.jsp?EID=236482
Created: Oct 25, 2000 Modified: 2000-10-25 11:19:34.19
Author: Tim Rohaly (http://www.jguru.com/guru/viewbio.jsp?EID=10) Question
originally posed by Declan Shanaghy
(http://www.jguru.com/guru/viewbio.jsp?EID=109967
The SUID is one of a number of things that the serialization protocol writes to the
stream in addition to the serialized object (other things include a magic number and
the fully- qualified class name of the object). SUID is not the same as the static
variable serialVersionUID, although SUID is computed using that field, if it exists.
In psuedocode,
1. The serialized object. This does not include the static member
serialVersionUID, but it does include the SUID, fully-qualified class name,
etc.
2. The .class file. This does include the static members.
When deserializing, the SUID embedded in the object input stream is compared to
the SUID computed from the local .class file according to the psuedocode above. If
the SUIDs are equal, then the serialized object is compatible with the class file
definition.
No. This is a common misconception. The deserialization process does not use the
object's constructor - the object is instantiated without a constructor and initialized
using the serialized instance data. The only requirement on the constructor for a
class that implements Serializable is that the first non-serializable superclass in its
inheritence hierarchy must have a no-argument constructor. (See
http://www.jguru.com/jguru/faq/view.jsp?EID=34802 for a more complete
explanation). This makes sense: deserialization needs to reconstruct the entire
object state, which includes the state of any superclasses. If the superclass is not
itself serializable, then deserialization needs to instantiate that superclass from
scratch - thus the requirement. For example, with the following class:
All the requirements for an object that implements Serializable are listed at
http://www.jguru.com/jguru/faq/view.jsp?EID=31434.
Throws java.io.InvalidClassException
Author: G R (http://www.jguru.com/guru/viewbio.jsp?EID=999272), Sep 14, 2002
Just wanted to correct that if the super class does not have a no argument constructor,
then following exception is thrown when you try to deserialize the class.
java.io.InvalidClassException: no valid constructor
There are limits, but in practice you shouldn't encounter them. You are limited by the
amount of memory your JVM can allocate to the creation and maintainence of your
object. As for writing it out to disk, you are limited by the maximum file size of the
underlying OS. Linux for example, has a 2GB limit on any one file.
See also:
• http://www.jguru.com/jguru/faq/view.jsp?EID=28713
How can I determine the byte length of an object that I serialize to a
stream?
Location: http://www.jguru.com/faq/view.jsp?EID=264462
Created: Nov 28, 2000 Modified: 2001-01-17 20:50:49.845
Author: Tim Rohaly (http://www.jguru.com/guru/viewbio.jsp?EID=10) Question
originally posed by Alan Cox (http://www.jguru.com/guru/viewbio.jsp?EID=255589
There are a couple of things you can do. First, you can pipe the ObjectOutputStream
into a ByteArrayOutputStream, then examine the length of the byte array:
Or, if you want to stream to a destination other than a byte array, you can write a
subclass of DataOutputStream which allows you to access the protected variable
written. This subclass can be used to monitor the data sent through the stream to
any destination source:
import java.io.*;
A big part of EJB is that it is a framework for underlying RMI: remote method
invocation. You're invoking methods remotely from JVM space 'A' on objects which
are in JVM space 'B' -- possibly running on another machine on the network.
To make this happen, all arguments of each method call must have their current
state plucked out of JVM 'A' memory, flattened into a byte stream which can be sent
over a TCP/IP network connection, and then deserialized for reincarnation on the
other end in JVM 'B' where the actual method call takes place.
If the method has a return value, it is serialized up for streaming back to JVM A.
Thus the requirement that all EJB methods arguments and return values must be
serializable. The easiest way to do this is to make sure all your classes implement
java.io.Serializable.
I think that serialization mechanism is not a good solution to that problem : it is slow
(no // between network, client and server) and it uses a lot of memory.
The stream header containing the magic number and version number are read from
the stream and verified. This method will block until the corresponding
ObjectOutputStream has written and flushed the header.
This is a very important point to be aware of when trying to send objects in both
directions over a socket because opening the streams in the wrong order will cause
deadlock.
Consider for example what would happen if both client and server tried to construct
an ObjectInputStream from a socket's input stream, prior to either constructing the
corresponding ObjectOutputStream. The ObjectInputStream constructor on the
client would block, waiting for the magic number and version number to arrive over
the connection, while at the same time the ObjectInputStream constructor on the
server side would also block for the same reason. Hence, deadlock.
Because of this, you should always make it a practice in your code to open the
ObjectOutputStream and flush it first, before you open the ObjectInputStream. The
ObjectOutputStream constructor will not block, and invoking flush() will force the
magic number and version number to travel over the wire. If you follow this practice
in both your client and server, you shouldn't have a problem with deadlock.
You can't. As messages are associated with folders which are associated with
sessions, Message objects are considered not serializable. Like threads and images
you need to save the pieces that are not session-specific and regenerate the object
at the other end. Save the contents to an RFC 822 formatted stream
(message.writeTo()), serialize the bytes, and recreate the message at the other end.
Where can I learn (more) about Java's I/O (input/output, IO) capabilities?
Location: http://www.jguru.com/faq/view.jsp?EID=431192
Created: May 30, 2001
Author: John Mitchell (http://www.jguru.com/guru/viewbio.jsp?EID=4)
Where can I learn (more) about Java RMI (Remote Method Invocation)?
Location: http://www.jguru.com/faq/view.jsp?EID=431242
Created: May 30, 2001
Author: John Mitchell (http://www.jguru.com/guru/viewbio.jsp?EID=4)
You need to pass in the array "type" after the [ character, and before a ; character. If
the type is a class, add the letter L and the fully qualified class name. If the type is a
primitive, the type codes are specified in ObjectStreamField.getTypeCode(), you can
almost just capitalize the first letter and place after [. Though, that isn't always the
case. For boolean, use Z instead of B, for long use J since L is already taken for
classes and interfaces.
serialver "[Ljava.lang.String;"
For an array of int elements, it is:
serialver "[I;"
import java.io.*;
public class CustomDataExample implements Serializable {
/**
* Create the triangular array of dimension dim and initialize it
*/
CustomDataExample (int dim) {
dimension = dim;
thearray = new int[dim][dim];
arrayInit();
}
/**
* Create an CustomDataExample object, serialize it, deserialize it
and
* see that they are the same. So, basically test that this custom
* data example's serialization works.
*/
public static void main(String args[]) {
CustomDataExample corg = new CustomDataExample(4);
CustomDataExample cnew = null;
/**
* Write out the dimension and 1/2 of the 2-dimensional array to the
* ObjectOutputStream s. readObject depends on this data format.
*
* @serialData Write serializable fields, if any exist.
* Write out the integer Dimension of the symetrical,
* two-dimensional array. Write out the integers
composing
* 1/2 of the 2-dimensional array.
*
*/
private void writeObject(ObjectOutputStream s)
throws IOException {
// Call even if there is no default serializable fields.
s.defaultWriteObject();
/**
* Read in the dimension and 1/2 of the 2-dimensional array from the
* ObjectInputStream s. Was written to by writeObject. Also, copy
the
* 1/2 array to the other half to completely fill the symmetric
array.
*
* @serialData Read serializable fields, if any exist.
* Read optional data consisting of an integer
indicating
* both dimensions of the 2-dimensional array. Read in
* 1/2 of the 2-dimensional array.
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
/* Call even if there is no default serializable fields.
* Enables default serializable fields to be added in
future versions
* and skipped by this version which has no default
serializable fields.
*/
s.defaultReadObject();
/**
* Initialize the array to some numbers starting from 0 - make it
* symmetrical
*/
void arrayInit() {
int x = 0;
for (int i = 0; i < dimension; i++) {
for (int j = 0; j <= i; j++) {
thearray[i][j] = x;
thearray[j][i] = x;
x++;
}
}
}
/**
* Print the 2-dimensional array. Useful for testing.
*/
public String toString() {
Use java.beans.XMLEncoder.
XMLEncoder e = new XMLEncoder(
new BufferedOutputStream(
new FileOutputStream("Test.xml")));
e.writeObject(new JButton("Hello, world"));
e.close();
Comments and alternative answers
I realize that Serialization is all about the current state of the object, and if the values
haven't changed then re-creating the object will automatically preserve state.
It just seems like it would have been a bit more usefull to have XML that is a true
descriptor of the object. R.
import java.beans.XMLEncoder;
import java.io.*;