Package java.beans

Contains classes related to Java Beans development.

See:
          Description

Interface Summary
ExceptionListener An ExceptionListener is notified of internal exceptions.
 

Class Summary
DefaultPersistenceDelegate The DefaultPersistenceDelegate is a concrete implementation of the abstract PersistenceDelegate class and is the delegate used by default for classes about which no information is available.
Encoder An Encoder is a class which can be used to create files or streams that encode the state of a collection of JavaBeans in terms of their public APIs.
EventHandler The EventHandler class provides support for dynamically generating event listeners whose methods execute a simple statement involving the incoming event object and a target object.
Expression An Expression object represents a primitive expression in which a single method is applied to a target and a set of arguments to return a result - as in "a.getFoo()".
PersistenceDelegate The PersistenceDelegate class takes the responsibility for expressing the state of an instance of a given class in terms of the methods in the class's public API.
Statement A Statement object represents a primitive statement in which a single method is applied to a target and a set of arguments - as in "a.setFoo(b)".
XMLDecoder The XMLDecoder class is used to read XML documents created using the XMLEncoder and is used just like the ObjectInputStream.
XMLEncoder The XMLEncoder class is a complementary alternative to the ObjectOutputStream and can used to generate a textual representation of a JavaBean in the same way that the ObjectOutputStream can be used to create binary representation of Serializable objects.
 

Package java.beans Description

Contains classes related to Java Beans development. A few of the classes are used by beans while they run in an application. For example, the event classes are used by beans that fire property and vetoable change events (see PropertyChangeEvent). However, most of the classes in this package are meant to be used by a bean editor (that is, a development environment for customizing and putting together beans to create an application). In particular, these classes help the bean editor create a user interface that the user can use to customize the bean. For example, a bean may contain a property of a special type that a bean editor may not know how to handle. By using the PropertyEditor interface, a bean developer can provide an editor for this special type.

To minimize the resources used by a bean, the classes used by bean editors are loaded only when the bean is being edited. They are not needed while the bean is running in an application and therefore not loaded. This information is kept in what's called a bean-info (see BeanInfo).

Long-term Persistence for JavaBeans

The new APIs in the java.beans package provide support for reading and writing a JavaBean as a textual representation of its property values. When these property values are themselves JavaBeans the process is called recursively to record the publicly available state of an entire graph of JavaBeans.

Goals

The following goals were established for creating a long term persistence scheme for JavaBeans:


A Note on Marshaling vs. Archiving

There are two main tacks to take in persistence schemes: The simplest scheme taking the first approach requires the inclusion of all the classes that define the objects -- which is too expensive. The practical alternative, which is to refrain from serializing the byte codes that define the classes themselves, is workable between identical implementations of the same libraries. The serialization framework in 1.1 implements this and is therefore the method of choice for sending faithful copies of an object graph between two similar VMs.

In this work we implement the second approach  - which cannot produce as faithful a copy of the original objects as the first but can store the state of the graph in such a way that any virtual machine with API-compatible implementations of the classes involved will be sufficient to reconstitute it. Since APIs are so much more stable than their private implementations, this single step virtually solves the versioning issues for most practical purposes. As importantly, from an deployment perspective, the behavior of the constructors residing on the client machine can be leveraged, often dramatically reducing the size of the files that need to be transferred.


The Persistence Model

The new streams read and write archives that depend only on the public APIs of the JavaBeans in the archive, and not on the state of any private implementation. Like modern programming languages, the implementation of the new streams deals with the syntactic and semantic elements of this task separately. This formal separation allows the majority of the internal architecture, and any special-case code that changes the way the state of a particular class is archived, to be written in a form that is independent of the syntax of the output.  Given both the proliferation of new XML standards and their rapid evolution, this accommodating rather than defining role seems to be the best way to provide JavaBeans with a long-term persistence strategy that can coexist with this evolutionary process.

Typically this architecture reduces the serialization problem for JavaBeans to the problem of providing an ordered list of properties that define the state of the JavaBean. All values of the properties of a JavaBean are assumed to be JavaBeans. To make this recursive definition work, we have to widen the notion of what is considered a JavaBean slightly so as to include all possible values that properties can take. In our implementation, Color objects are considered to be JavaBeans, as are LayoutManagers, Vectors, Hashtables, Numbers, and Boolean values. To handle the "wiring" part of the user interface it has also proven convenient to provide built-in support for some other key classes in the JDK including Method, Class, array classes, and proxy classes.

To handle all these extra classes the first requirement is that we are able to create instances of them. In all the special cases, where no nullary constructor is defined, this requires extra information that describes how a new instance should be created. For most classes this extra information simply associates the arguments of a chosen constructor with names of the properties they represent. So, for example, the java.awt.Color class is augmented with meta data recording the fact that the three integers that appear as arguments in one of the constructors are the red, green, and blue properties of the new instance. Given this extra information the recording of a Color object is reduced to the simpler problem of recording the Integer values of those properties.

In other cases, such as java.lang.Method, the extra information is used to indicate to the output stream the fact that, instead of using a constructor, the static getMethod method in java.lang.Class should be used to retrieve instances of the Method class. Near the bottom of these recursive definitions are the wrappers for the primitive types of the Java virtual machine: the Boolean class and the Number derivatives. All of these classes have a useful invariant in that they may be reconstructed by calling their single-argument constructor using the value returned by the toString method.  Closing this recursive definition then, is the java.lang.String class, for which each file format must provide built-in support, and in terms of which all other objects will be represented.

In addition to the need to be able to specify the manner in which an object should be instantiated it is also necessary to find a general way to describe the way it should be initialized. This allows the user to accommodate "hidden state" which is not represented as properties but which is central to the public behavior of an object. An instance of the java.awt.Container class, for example, should have all of its children recorded if it is expected to behave like the original.

Architecture

Critical to dealing with these special cases and providing a means by which the application programmer can provide their own persistence for new JavaBeans with similar anomalies are two new public classes in the beans package: the Expression and the Statement. Both of these new classes present simple abstractions of the single-method expressions and statements that one might expect to find in a java source program. The new output stream works by providing an architecture in which the object graph is cloned - exclusively by using Expression and Statement objects in a new environment. If this cloning process is successful, a record of the Expressions and Statements used to duplicate the object graph may be encoded into a textual format and put in a file which is then capable of creating the object graph on its own.

Identity

As the object graph is traversed a hashtable (actually a special kind of hashtable that uses "==" instead of "equals") is used to detect when a node is revisited. When it is, the stream gives this instance a name so that it can be referred to multiple times in the archive. That way the identity of objects in the graph is preserved by the archival process.

Size

Even though an XML encoding, term for term, takes significantly more space than a binary encoding, the archives produced by the new streams are typically between 10x and 100x smaller than their serialized counterparts. This is due to a comprehensive system for excluding default information from the archives.

Listeners

A crucial part of a user interface, beyond the way it will appear, is the way it will be connected to the logic of an application. In the past this has only been possible by generating Java source files that implement event listener interfaces and compiling  them at design time. With the introduction of the java.lang.reflect.Proxy API's in SDK 1.3 it is now possible to consider the "wiring" of the user interface as part of the state of the design and saved as an integral part of archive that represents it.

The new EventHandler class provides a convenient and concise way to make use of the Proxy APIs to create listeners for JavaBeans. Most importantly, this "trampoline" class has both a public constructor and accessors for all internal state that is required to produce it. Such classes, unlike anonymous inner classes, can therefore be archived in the same way that any other bean is archived: as a textual representation of the public API needed to create it.

Summary

The new input and output streams complement the binary serialization support that was introduced in JDK 1.1 with support for a human readable format. The new streams have been implemented to a set of design goals that make them more suitable than binary serialization as a persistence mechanism for user interfaces. Committing the archives to the public APIs of the classes to which they refer makes the archives inherently more robust than those that contain private state. The redundancy elimination system used in the new streams makes the new formats attractive in that they are both human-readable and, in most cases, one or two orders of magnitude smaller than their binary equivalents.