Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional Java.JDK.5.Edition (Wrox)

.pdf
Скачиваний:
39
Добавлен:
29.02.2016
Размер:
12.07 Mб
Скачать

Chapter 5

Some of the potential downsides to choosing the XMLEncoder/Decoder for serializing your object graph of Java Beans follow:

Even though the file format is human-readable, it is editable in the real world only by developers or power users.

Even though the file format is XML, it is still Java-specific — it would take great effort to allow a non-Java-based application to read the data.

Every piece of data you want persisted in the class must be a Java Bean property (or customized with a special persistence delegate).

The XMLEncoder/Decoder API is perfect for what it is designed for — the long-term serialization of Java Beans components for use later on by Java-based applications. Because it is so customizable, it can often be used for a variety of other purposes, and serialize a lot of data beyond ordinary Java Beans. Generally, though, its main advantage over normal Java Serialization is its robustness, even through class definition changes. Apart from that, however, it still has the same limitations of the Java Serialization API. When you have an internal data model based with Java Beans, XMLEncoder/Decoder makes sense. If you would like your application’s file formats to be read by other non-Java applications, eventually you will have to specify some other custom file format or write to an existing standard.

XML Schema-Based Serialization:

Java API for XML Binding (JAXB)

The last method to be discussed in this chapter for persisting an application’s data is the Java API for XML Binding (JAXB). This method is fundamentally different from the other two serialization methods that have already been discussed (the Java Serialization API and the XMLEncoder/Decoder API). Both of these models involve taking a data model consisting of classes already defined and persisting instances of these classes. Later on, the information on disk could then be used to reconstruct the object graph back into the in-memory model used by an application. Both of these models map Java classes to a file format. JAXB takes the opposite approach. It maps a file format to Java classes. The diagram shown in Figure 5-10 illustrates this difference.

 

 

 

 

JAXB Generated Class

 

 

 

Serialization

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Java Serialization API writes

Binary Format

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

JAXB writes

 

 

 

 

 

 

User Defined Java Class

 

 

JAXB generates

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

XMLEncoder

 

User Defined

 

 

Generic XML

XMLEncoder/Decoder API writes

 

 

 

Bean XML

 

XML Schema

 

 

Format

 

 

 

 

 

 

 

 

 

 

Format

 

 

 

Schema defines

Figure 5-10

256

Persisting Your Application Using Files

Instead of defining Java classes, which in turn are written to predefined file formats, the developer defines the file format in the XML schema language. Once the file format is defined, JAXB generates a set of Java classes that read and write the XML instance documents that correspond to the defined XML schema.

The XML schema language is the World Wide Web Consortium’s standard for defining XML instance documents of a particular type. It is a widely accepted standard and already defines many different types of XML documents. XML schemas also let XML parsers validate an XML instance document to verify that they conform to the schema’s requirements. This can greatly reduce the time it takes to write code that must read XML, as it does a lot of the validation for you. View the XML schema specification at the following URL: http://www.w3.org/TR/xmlschema-0/.

JAXB generally requires more work on the part of the developer. The benefit is that other applications can easily read and write the data model defined by the XML schema. Because XML schema is a wellaccepted standard, other languages and development languages also have tools to generate data storage classes based on an XML schema. This makes JAXB ideal for applications that must share a common data format. When other applications specify their file formats in XML schema, JAXB makes life simple for the developer, since the developer already has a file format specification defined and simply has to generate the Java classes that bind to XML documents that follow the schema.

Since JAXB generates Java classes based on a particular XML schema, the developer does not have as much room to customize the data structure. In most cases, developers will find themselves going back to the XML schema, modifying it, and regenerating the classes’s additional information or changes to current information that must be stored. Generated code provides a set of different issues for the developer. Names for data members, while following the schema, can be tedious to work with, and code using generated classes can easily become difficult to read. Many times developers will be forced with the additional burden of mapping data in JAXB-generated classes to classes in the JDK — like mapping color information to a java.awt.Color instance, or constructing a java.net.URL or file path from a String. This additional overhead is one of the downsides of JAXB — it is usually worth the effort though, if interoperability and a readable file format are requirements of your application. The quick and easy days of the Java Serialization API and the XMLEncoder/Decoder API give way to the slightly more tedious JAXB methodology of programming. Anytime you need to interface with non-Java applications, the complexity increases.

Sample XML Document for Your Configuration Object

Suppose you want to take your Configuration data model and define an XML schema to represent it. You will not be able to write an XML schema that maps directly to your already-existing Configuration class, but you can write an XML schema that saves all the necessary data attributes to

recreate your Configuration instance. This is where the extra effort comes in on the part of the developer. After the in-memory data model is defined, in your case the Configuration object, an XML schema must additionally be defined to represent all the necessary data attributes to recreate it. If you did not already have a class for your Configuration data model, you would still have to write some sort of conversion between types like java.awt.Color and the JAXB class that you generate with that same information — after all, other Swing classes were developed to interact with java.awt.Color, not whatever custom class JAXB decides to generate for you! To refresh your memory on what data attributes are stored in Configuration, Figure 5-11 is the original data model diagram displayed earlier in the chapter.

257

Chapter 5

Configuration

 

 

 

-userHomeDirectory : string

 

 

 

-showTabs : bool

1

 

 

-recentFiles : string[]

2

-paletteWindowPosition, toolsWindowPosition

 

 

 

1

 

java.awt.Point

 

-…

 

 

 

 

-backgroundColor, foregroundColor

java.awt.Color

-…

2

Figure 5-11

Essentially, data representing a color, a point, directory and file locations, and a boolean variable needs to be stored. XML schema is more than equipped to handle this — you just have to actually define it. Below is an XML instance document that contains all of the information you would need to recreate your Configuration object. Notice how it is not only human-readable in the sense that it is text, but it is also conceivably modifiable by a user. Colors are obviously defined, and the user’s home directory is easily modified. The XML below is far more readable than the output from the XMLEncoder/Decoder API:

<?xml version=”1.0” encoding=”UTF-8” standalone=”yes”?> <configuration xmlns=”http://book.org/Configuration”>

<user-settings>

<user-home-directory>C:\Documents and Settings\Mark\My Documents</user-home- directory>

<recent-files> <recent-file>c:\mark\file1.proj</recent-file>

<recent-file>c:\mark\testproj.proj</recent-file>

<recent-file>c:\mark\final.proj</recent-file> </recent-files>

</user-settings>

<ui-settings> <palette-window-position>

<x-coord>5</x-coord>

<y-coord>5</y-coord> </palette-window-position>

<tools-window-position>

258

Persisting Your Application Using Files

<x-coord>10</x-coord>

<y-coord>10</y-coord> </tools-window-position>

<background-color> <red>51</red>

<green>51</green>

<blue>255</blue>

<alpha>255</alpha> </background-color>

<foreground-color> <red>255</red>

<green>255</green>

<blue>51</blue>

<alpha>255</alpha> </foreground-color>

<show-tabs>true</show-tabs> </ui-settings>

</configuration>

Note though, that this XML file is not the XML schema; it is a document that conforms to the XML schema defined in the next section of this chapter. JAXB will generate Java classes that read and write files like the preceding XML conforming to your schema. It will give you Java Bean–like access to all of the data contained in the document.

Defining Your XML Format with an XML Schema

Now that you have looked at a sample XML instance document containing a sample set of Configuration data for your data model, you can look under the hood and see how to specify the file format. In this section, the various data types for your configuration will be analyzed and then defined in a schema. To reiterate the following data is necessary to store in your configuration data model:

The user’s home directory, a string value

A flag whether or not to use a tabbed interface, a boolean value

A list of recently accessed files by the user, an array of string values

Two colors, foreground and background, for drawing operations, color values

Two points, for the last position of the tool and palette windows, point values

While this section will not be a thorough guide in any sense to XML schema, you will go through how to define the data bullets listed earlier. First, though, XML schema must be briefly discussed. XML schema is a simple but powerful language for defining and specifying what types various XML elements can be,

259

Chapter 5

and where they can appear in a document. Essentially, there are two types of XML elements you can define with XML schema: simple elements and complex elements. Simple elements have no attributes and contain only text data — they also have no child elements. An example of a simple element follows:

<hello>world</hello>

Complex elements can have attributes, child elements, and potentially mix their child elements with text. The following is an example of a complex element:

<complex c=”12”> <hello>world</hello>

</complex>

XML schema is fairly intuitive, but a full and thorough coverage of it is beyond the scope of this book. A great online tutorial can be found at the following URL:

http://www.w3schools.com/schema/default.asp

Defining Your Data: Configuration.xsd

To define your data, you will be using both simple and complex elements. Looking back at the bullet list of data points necessary, both the user’s home directory and your tabbed interface flag (the first two bullets) can probably be modeled with simple elements. Here is how you will model them in XML schema:

<xs:element name=”user-home-directory” type=”xs:string” />

<xs:element name=”show-tabs” type=”xs:boolean” />

You are defining elements and requiring that the text within those elements be of the type specified. An instance example of both of these elements follows:

<user-home-directory>c:\mark</user-home-directory>

<show-tabs>true</show-tabs>

The string array of recent files is slightly more complex to model. It will be modeled as a complex element, with a child element for each individual recent file. First, you define your complex type:

<xs:complexType name=”recentFilesType”> <xs:sequence>

<xs:element name=”recent-file” type=”xs:string” maxOccurs=”unbounded” /> </xs:sequence>

</xs:complexType>

After defining your complex type, which is a sequence of recent-file elements, you can define your element that uses your custom XML type. Note how the type attribute in the element definition that follows corresponds to the name attribute in your preceding complex type definition:

<xs:element name=”recent-files” type=”recentFilesType” minOccurs=”0” />

260

Persisting Your Application Using Files

An example instance of your recent-files element looks like the following:

<recent-files> <recent-file>c:\mark\file1.proj</recent-file>

<recent-file>c:\mark\testproj.proj</recent-file>

<recent-file>c:\mark\final.proj</recent-file> </recent-files>

Defining colors presents an interesting challenge. You must make sure you have enough information specified in the XML file to construct a java.awt.Color object. If you specify in the XML file the red, green, blue, and alpha components of a color, you will have enough information to construct a java.awt.Color instance. The color type can then be modeled as follows:

<xs:complexType name=”colorType”> <xs:sequence>

<xs:element name=”red” type=”xs:int” />

<xs:element name=”green” type=”xs:int” />

<xs:element name=”blue” type=”xs:int” />

<xs:element name=”alpha” type=”xs:int” default=”255” /> </xs:sequence>

</xs:complexType>

As you can see, your complex type (colorType) contains child elements for the RGBA components. These components are integer values and if the alpha component is not specified, it defaults to 255 (a totally opaque color). After defining two elements that take your newly defined type (colorType), the foreground and background colors for your application’s configuration data model can be declared:

<xs:element name=”background-color” type=”colorType” minOccurs=”0” />

<xs:element name=”foreground-color” type=”colorType” minOccurs=”0” />

An example instance of a foreground-color element is shown as follows:

<foreground-color> <red>255</red>

<green>255</green>

<blue>51</blue>

<alpha>255</alpha> </foreground-color>

The last major custom type you must define is your type for point objects. This type must have enough information encoded in the XML to construct a java.awt.Point instance. All you essentially need are integer values representing the x and y coordinates of a point. The last two element definitions that use your new XML type for points, pointType, are also listed below. These elements represent the positions of the palette window and the tool window of your application:

261

Chapter 5

<xs:complexType name=”pointType”> <xs:sequence>

<xs:element name=”x-coord” type=”xs:int” />

<xs:element name=”y-coord” type=”xs:int” />

</xs:sequence>

</xs:complexType>

<xs:element name=”palette-window-position” type=”pointType” minOccurs=”0” /> <xs:element name=”tools-window-position” type=”pointType” minOccurs=”0” />

Now that you have defined all of your basic types in your schema, they can be organized around other elements for better readability of your XML instance documents. The actual schema listed at the end of this section will have more element and complex type definitions to account for document readability. The next step will be to generate JAXB classes from your schema in order to start reading and writing XML documents that conform to your schema.

The full XML Schema Definition (XSD) file for your configuration data model, configuration.xsd, is listed as follows:

<?xml version=”1.0” encoding=”utf-8” ?>

<xs:schema targetNamespace=”http://book.org/Configuration” elementFormDefault=”qualified” xmlns=”http://book.org/Configuration” xmlns:xs=”http://www.w3.org/2001/XMLSchema”>

<xs:complexType name=”configurationType”> <xs:sequence>

<xs:element name=”user-settings” type=”user-settingsType” />

<xs:element name=”ui-settings” type=”ui-settingsType” /> </xs:sequence>

</xs:complexType>

<xs:complexType name=”recentFilesType”> <xs:sequence>

<xs:element name=”recent-file” type=”xs:string” maxOccurs=”unbounded” /> </xs:sequence>

</xs:complexType>

<xs:complexType name=”pointType”> <xs:sequence>

<xs:element name=”x-coord” type=”xs:int” />

<xs:element name=”y-coord” type=”xs:int” /> </xs:sequence>

</xs:complexType>

<xs:complexType name=”colorType”> <xs:sequence>

<xs:element name=”red” type=”xs:int” />

<xs:element name=”green” type=”xs:int” />

<xs:element name=”blue” type=”xs:int” />

262

Persisting Your Application Using Files

<xs:element name=”alpha” type=”xs:int” default=”255” /> </xs:sequence>

</xs:complexType>

<xs:complexType name=”ui-settingsType”> <xs:sequence>

<xs:element name=”palette-window-position” type=”pointType” minOccurs=”0” />

<xs:element name=”tools-window-position” type=”pointType” minOccurs=”0” />

<xs:element name=”background-color” type=”colorType” minOccurs=”0” />

<xs:element name=”foreground-color” type=”colorType” minOccurs=”0” />

<xs:element name=”show-tabs” type=”xs:boolean” /> </xs:sequence>

</xs:complexType>

<xs:complexType name=”user-settingsType”> <xs:sequence>

<xs:element name=”user-home-directory” type=”xs:string” />

<xs:element name=”recent-files” type=”recentFilesType” minOccurs=”0” /> </xs:sequence>

</xs:complexType>

<xs:element name=”configuration” type=”configurationType” />

</xs:schema>

Generating JAXB Java Classes from Your Schema

Generating JAXB classes from an XML schema requires the Java Web Services Development Pack from Sun. The latest version of JWSDP from Sun is version 1.4 and version 1.0 of the JAXB specification (implemented by version 1.03 of Sun’s reference implementation). Sun’s reference distribution of JAXB includes an XML schema compiler. This compiler outputs Java classes that read and write the particular XML schema from which they were generated. The JWSDP installer can be downloaded from Sun’s Web site from the following URL:

http://java.sun.com/webservices/jwsdp/index.jsp

Installing it is straightforward, as it installs much like any Windows application. JWSDP includes many tools besides JAXB, but JAXB is all that will be discussed in this chapter. To use the XML schema compiler, you must make sure your PATH environment variable includes the /jaxb/bin directory under the folder where you installed JWSDP. Sun’s compiler is called by the xjc batch file located in the /jaxb/bin directory. Once it is on your PATH, running it is straightforward. You saved your schema to the file configuration.xsd. To compile your schema, you simply type the following at the command prompt:

xjc –d gen configuration.xsd

263

Chapter 5

The -d option simply tells the compiler in which directory to put the generated Java source files. In your case, you have a directory under your main project specifically for generated source files, gen, so that if you modify your schema, you can easily regenerate the files to this same location. Figure 5-12 shows the output of the xjc compiler.

Figure 5-12

After the xjc compiler is run to compile your schema, the following Java source files and resources are generated:

org\book\configuration\bgm.ser

org\book\configuration\ColorType.java

org\book\configuration\Configuration.java

org\book\configuration\ConfigurationType.java

org\book\configuration\jaxb.properties

org\book\configuration\ObjectFactory.java

org\book\configuration\PointType.java

org\book\configuration\RecentFilesType.java

org\book\configuration\UiSettingsType.java

org\book\configuration\UserSettingsType.java

org\book\configuration\impl\ColorTypeImpl.java

org\book\configuration\impl\ConfigurationImpl.java

org\book\configuration\impl\ConfigurationTypeImpl.java

org\book\configuration\impl\JAXBVersion.java

org\book\configuration\impl\PointTypeImpl.java

org\book\configuration\impl\UiSettingsTypeImpl.java

org\book\configuration\impl\UserSettingsTypeImpl.java

Note: There are also many Java sources generated in the org\book\configuration\impl\runtime folder. These sources are required in addition to the JAXB library JAR files at run time. You will not be analyzing them or their content, however; just be aware that they are necessary at run time. There is a com- mand-line option to disable the runtime package generation — if you generate classes for more than one schema, you only need to reference one runtime package. In those scenarios, the runtime classes are not needed (though you will need to pass along where a current runtime package exists for the xjc compiler to disable the generation of the runtime package).

264

Persisting Your Application Using Files

Generated JAXB Object Graphs

JAXB generates its classes to follow certain conventions that correspond to how an XML schema is written. Package names for generated classes follow whatever XML namespace the elements have in the schema (though the package names can be changed with a certain command-line argument to the xjc compiler). Every top-level XML element or complex type defined in a schema gets its own interface in the root package generated by JAXB. A top-level element or complex type in an XML schema is one that is not nested in other elements — its definition is a direct child element to the root element of the schema definition. For example, in your schema, the complex type pointType is a top-level definition because its location in the schema is right under the parent schema definition element. The only interface that represents an element definition in your list of generated files is the org.book.configuration

.Configuration interface. This interface corresponds to the following element definition from the schema:

<xs:element name=”configuration” type=”configurationType” />

Note: The type org.book.configuration.Configuration is different from the type book.Configuration that has been referred to in the earlier sections of this book (though it represents the same logical data points). The type org.book.configuration.Configuration is the JAXB-generated class that represents the data defined in your XML schema.

As you can see, the name of the interface comes from the name of the element. Every top-level element in a schema definition gets its own interface that extends the interface javax.xml.bind.Element. This is JAXB’s way of marking that a particular interface is a top-level element in an XML schema. It is similar in concept to java.io.Serializable, in the sense that it contains no methods. It is also similar because in JAXB, you cannot serialize or deserialize any structure that is not a javax.xml.bind

.Element (much like you cannot use the Java Serialization API to serialize any class not marked Serializable). This is important to know, because when you define your schema, you must have at least one top-level element definition. These top-level element definitions are potential root elements in an XML instance document.

You may have guessed by now that the rest of the root package org.book.configuration consists mainly of all interfaces. That is the case, and the org.book.configuration.impl package contains the implementations of these interfaces. The rest of the interfaces in your package all correspond to top-level complex type definitions in your schema. A couple of them will be looked at in detail, namely ColorType and PointType. Any interface that represents a complex type definition will have the Type suffix appended to the complex type name, hence your interfaces PointType and ColorType represent the complex schema types pointType and colorType, respectively (the generator is smart enough not to make the name PointTypeType, since you already appended type to the name of your complex type definitions in the schema; see Figure 5-13).

As you can see from the diagram in Figure 5-13, JAXB maps XML elements and attributes of complex types to Java Bean properties. The complex type colorType in the schema had four subelements: red, blue, green, and alpha. These were all mapped to Java Bean int properties. They were mapped to int because that was the type specified in their element definitions. Their type could also potentially be another complex type, which would map to another generated JAXB interface, rather than a Java primitive type like int.

265

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]