Long Term Persistence of JavaBeans
Components:
|
try {
XMLDecoder d = new XMLDecoder(
new BufferedInputStream(
new FileInputStream("Browse.xml")));
d.readObject();
d.close();
} catch (IOException e) {
...handle the exception...
}
|
For a ready-made program that reads XML archives, see TestInput.java.
Sample scripts for running it on Win32 and UNIX are in xml.bat
and xml, respectively.
<java>
tag.
<?xml version="1.0" encoding="UTF-8" ?> <java version="1.4.0" class="java.beans.XMLDecoder"> ...objects go here... </java>
The <java> element contains two informational
attributes (not currently used by XMLDecoder): the
version attribute, which records the version of the
Java platform that was used to
write the archive, and the class attribute, which specifies
the class of the decoder for which the document was written. The
objects that the archive contains make up the body of this element
and appear in the order they will be returned by calls to the decoder's
readObject method.
Objects are represented by the sequence of method calls that will be used to create them. Each element in the XML document represents a method call that either creates an object (an expression) or has a side effect on an object (a statement). Strings are treated as special kinds of expressions. Identifiers name objects so they can be referred to after their creation.
Strings are the atomic expressions of the XML document. The characters
in a string form the body of an element with the <string>
tag. For example, the string "Hello, World" is represented
by the following XML code:
<string>Hello, World</string>
The '<' and '&' characters are
represented by the < and &
escape sequences.
<object> tag; each statement
is represented by the <void> tag. For both <object>
and <void> tags, the method attribute
specifies the name of the method to be called when the document is
read.
The class attribute can be used in <object>
tags to specify a class as the target of a static method. Constructors
are represented as static methods that have the name new.
When an expression or statement contains expressions, the contained
expressions are used as arguments to the method represented by the
outer expression or statement. For example, to create an instance
of the JButton class we can write the following:
Because the enclosed element represents a string, which is an expression, the value<object class="javax.swing.JButton" method="new"> <string>Press me</string> </object>
"Press me" is used as an argument to the constructor
of the JButton class. The equivalent code written in
the Java programming language ("Java code") would be:
new JButton("Press me");
The default method name is new. It can therefore be omitted,
yielding the equivalent:
When statements appear inside the body of an expression, the statements are applied to the enclosing object after it is created. To execute a method with a side effect on an object we place the method inside the object to be affected. For example:<object class="javax.swing.JButton"> <string>Press me</string> </object>
This corresponds to the following code fragment:
<object class="javax.swing.JButton"> <void method="setText"> <string>Hello, world</string> </void> </object>
JButton b = new JButton();
b.setText("Hello, world");
If an expression should not be used as an argument to the enclosing
method, it should be represented with the <void> tag.
The result of an expression in a <void> tag is still
evaluated and used by any objects it encloses.
When an expression contains <void> tags (whether
they denote expressions or statements) without class
attributes, those <void> tags must follow all other
tags in the expression. Each non-<void> expression
is evaluated and the enclosing method is called with the results
as arguments. The <void>-tagged statements and expressions
are then applied, in order, to the result.
For example, consider the following expression:
It could be written as follows:
<object class="javax.swing.JButton"> <string>Press me</string> <void method="setName"> <string>Greeting</string> </void> </object>
JButton button1 = new JButton("Press me");
button1.setName("Greeting");
The ability to nest expressions and statements greatly reduces the number of identifiers that are needed to represent a given graph.
id
attribute, which binds a name to the expression value. The identifier
has global scope extending from the last argument of the expression
to the end of the file. In a streamed environment, the scope extends
until the stream is flushed.
The following expression creates an identifier button1,
bound to an instance of the JButton class:
Reference is made to named instances by using an<object id="button1" class="javax.swing.JButton"/>
idref
attribute in an element with the <object> tag. The
expression defining the identifier must precede any reference made
to that identifier. The following expression makes reference to a
previously defined instance button1:
The expression<object idref="button1"/>
corresponds to the following Java code:
<object class="javax.swing.JPanel"> <void method="add"> <object id="button1" class="javax.swing.JButton"/> </void> <void method="add"> <object class="javax.swing.JLabel"> <void method="setLabelFor"> <object idref="button1"/> </void> </object> </void> </object>
The
JPanel panel1 = new JPanel(); JButton button1 = new JButton(); JLabel label1 = new JLabel(); panel1.add(button1); panel1.add(label1); label1.setLabelFor(button1);
id attribute can be used with a <void>
tag when the tag denotes an expression, rather than a statement. This
allows you to make a reference to the result of an expression without
contributing to the arguments of the enclosing method.
For example, consider the following fragment:
It allows an expression to be evaluated in the context of the enclosing instance, in this case defining the variable<object class="java.util.Date"> <void id="now" method="getTime"/> </object>
now as the
value of the expression. It corresponds to the following Java code:
long now = new Date().getTime();
The preceding information is all you need to be able to write
XML archives readable by XMLDecoder. To read all archives
produced by XMLEncoder, however, you need to know about
the abbreviations for primitives, null, Class
objects, static constants, properties, indexes, and arrays.
toString method of
the wrapper class. Except for char, the body of the expression
is supplied to the constructor of the corresponding wrapper that takes
a single, String argument. The char type
is handled as a special case since no string constructor exists in
its wrapper class, Character.
The following tags represent both the primitive types and their corresponding wrapper classes:
<boolean><byte><char><short><int><long><float><double>is shortened to<object class="java.lang.Integer"> <string>123</string> </object>
which might represent either of the following Java code fragments:<int>123</int>
new Integer("123")
123
null, use the <null> tag.
A null element has no attributes and contains no other
tags. For example:
<null/>
<class> tag can be used to represent an instance
of Class. For example,
is shortened to<object class="java.lang.Class method="forName"> <string>java.awt.event.ActionListener</string> </object>
<class>java.awt.event.ActionListener</class>
which is equivalent to ActionListener.class.
class and field
attributes to specify the declaring class and field name of the constant,
respectively. Thus
is shortened to
<void class="javax.swing.JTable" method="getField"> <string>AUTO_RESIZE_OFF</string> <void id="Integer0" method="get"> <null/> </void> </void> <object idref="Integer0"/>
<object class="javax.swing.JTable" field="AUTO_RESIZE_OFF"/>
which represents JTable.AUTO_RESIZE_OFF.
get and set
can be written using the property attribute instead of
the method attribute.
For expressions with methods whose names begin with "get", the property name is the method name with "get" removed and the next letter made lowercase. Thus
is shortened to:<void method="getText"/>
<void property="text"/>
For statements with methods whose names begin with "set", the property name is derived in a similar way. Thus
is shortened to:<void method="setText"> <string>Hello, world</string> </void>
<void property="text"> <string>Hello, world</string> </void>
get or set, as defined
in the java.util.List
interface, can be written using the index attribute instead
of the method attribute.
For expressions with the method name get, the value
of the index attribute is used as the argument. Thus
is shortened to<void method="get"> <int>3</int> <void>
which corresponds to the following Java code:<void index="3"/>
Object o = aList.get(3);
For statements with the method name set, the value
of the index attribute is prepended to the arguments
of the enclosed body. Thus
is equivalent to<void index="3"> <string>Hello, world</string> </void>
which corresponds to the following Java code:<void method="set"> <int>3</int> <string>Hello, world</string> </void>
aList.set(3, "Hello, world")
<array> tag can be used to represent arrays. The
class and length attributes denote the subtype
and the length of the array respectively. You can use an id
attribute to name the array. Here is an example of using an <array>
tag:
It corresponds to the following Java code:<array class="java.awt.Component" length="3"/>
TheComponent[] a = new Component[3];
set and get methods, as defined in the
java.util.List interface, can be used as if they could
be applied to array instances. The index attribute can
thus be used with arrays.
Thus the expression
is equivalent to the following:<array class="java.lang.String" length="3"> <void index="1"> <string>Hello, world</string> </void> </array>
String[] s = new String[3]; s[1] = "Hello, world";
After the 1.4.0 beta release, you can omit the
length attribute from an <array> tag
and specify the values of entries directly, without using void
tags. The length of the array is equal to the number of values specified.
For example,
represents the following Java code fragment:<array class="int"> <int>123</int> <int>456</int> </array>
int[] intArray = {123, 456};
<java>)
element is evaluated in the context of the decoder itself. Typically
this outer context is used to retrieve the owner of the decoder,
which can be set before reading the archive. (See the API documentation
of XMLDecoder
and XMLEncoder
for details of the setOwner and getOwner
methods.) The owner is a property of the decoder
and can be accessed in the usual way:
<?xml version="1.0" encoding="UTF-8" ?> <java version="1.4.0" class="java.beans.XMLDecoder"> <void id="myController" property="owner"/> ...objects go here... </java>
The myController identifier can then by used throughout
the body of the document to refer to the owner of the decoder. The
following XML code creates a button that calls a no-argument doIt
method on the owner when the button is pressed:
<?xml version="1.0" encoding="UTF-8" ?> <java version="1.4.0" class="java.beans.XMLDecoder"> <void id="myController" property="owner"/> <object class="javax.swing.JButton"> <void method="addActionListener"> <object class="java.beans.EventHandler" method="create"> <class>java.awt.event.ActionListener</class> <object idref="myController"/> <string>doIt</string> </object> </void> </object> </java> |
It is also possible to use the top-level environment to produce
side effects on the owner. Typically this is used to set property
values on the owner to supply it with references to parts of a user
interface so that the owner can manipulate the UI programatically.
The following XML code creates a button and assigns it to the quitButton
property of the owner by calling the setQuitButton
method on the owner when the file is read.
<?xml version="1.0" encoding="UTF-8" ?> <java version="1.4.0" class="java.beans.XMLDecoder"> <void property="owner"> <void property="quitButton"> <object class="javax.swing.JButton"/> </void> </void> </java>
XMLEncoder for saving archives of beans. A DTD
that describes the syntax of the schema is in the file javabeans.dtd.
|
| ||||||||||||