Serialize Java Data Objects to XML (Continued)
Note that the same "stuff" object was added to the HashMap twice (as indicated in bold), but the XML shows it was saved once with an object id. This use of object id references is important, not only to save space, but because it prevents circular references such as those that might occur in graphs from blowing up because of infinite recursion. The persistence mechanism also knows how to save ordinary arrays and Vectors.
The fact that the XML text can be stored in a varchar instead of a BLOB in a SQL database is a significant plus, and you can see how to use a ByteArrayOutputStream (see Listing 4). The toString() method would produce a String of the XML, which can be written into a varchar or text field in a database. When you read it back, use the getBytes() method on the String object as the argument to the ByteArrayInputStream constructor and decode normally.
The persistence mechanism uses introspection to determine what to save from a regular JavaBean. Since time immemorial, long before JDK 1.4, there has been an Introspector class with static methods for obtaining BeanInfo objects. Therefore, if some object you want to save is not quite a bean because it has nonstandard get and set methods, you can create a [classname]BeanInfo class as part of your package. Its name is always the name of your class with BeanInfo appended. You don't have to register it with the Introspector. If it is in your package, that is, in a jar file you distribute, the Introspector will find it. Bean info classes can contain a lot of information that isn't relevant to persistence, and they can be tedious to write.
If you use an integrated development environment (IDE) you may have a wizard that will prepare BeanInfo classes for you that can be edited easily. Suppose the Stuff class also had a double named d as a property but had what() and force() methods instead of the getD() and setD() methods. Listing 5 shows part of the StuffBeanInfo class generated by Borland's JBuilder with the what() and force() methods added. Note that if you rely on a custom BeanInfo class when the XMLEncoder runs, then you should be sure the BeanInfo class is also available to whatever program runs the XMLDecoder. An alternative to the StuffBeanInfo is the StuffPersistenceDelegate in Listing 6 that will be explained shortly. For objects that are not even close to being a bean, we'll use the full power of persistence delegates.
Complex Designs
The encoder knows how to save many nonbean classes by using built-in metadata information about the class. The information is kept in a table of persistence delegates. The source file, on Windows, for this list of built-ins can be found in the file MetaData.java in the src.zip archive that can be found in the root directory of JDK 1.4 after you install it. Use WinZip or another zip file examiner to look at the file. The built-in delegates can serve as examples for those you might write or as guides to understanding any problems that may occur for saving complex GUI designs.
If you try to save an object that is not a bean and does not already have a built-in persistence delegate, the encoder may save nothing but the class name. There will be no error message, but looking at the XML file or trying to restore it will reveal that the state of the object wasn't saved. You may create PersistenceDelegate objects and add them to the static metadata through any XMLEncoder object. For example:
XMLEncoder e = new XMLEncoder(
System.out);
Back to top
|