JDO requires that you accompany each persistence-capable class with JDO metadata. This metadata serves three primary purposes:
To identify persistence-capable classes.
To override default JDO behavior.
To provide the JDO implementation with information that it cannot glean from simply reflecting on the persistence-capable class.
Metadata is specified as a document in the eXtensible Markup Language (XML). The Document Type Definition (DTD) for metadata documents is given in the next section. Do not worry about digesting the entire DTD immediately; we will fully cover each aspect of metadata in turn.
<!ELEMENT jdo (package)+> <!ELEMENT package ((class)+, (extension)*)> <!ATTLIST package name CDATA #REQUIRED> <!ELEMENT class (field|extension)*> <!ATTLIST class name CDATA #REQUIRED> <!ATTLIST class identity-type (application|datastore|none) 'datastore'> <!ATTLIST class objectid-class CDATA #IMPLIED> <!ATTLIST class requires-extent (true|false) 'true'> <!ATTLIST class persistence-capable-superclass CDATA #IMPLIED> <!ELEMENT field ((collection|map|array)?, (extension)*)> <!ATTLIST field name CDATA #REQUIRED> <!ATTLIST field persistence-modifier (persistent|transactional|none) 'persistent'> <!ATTLIST field primary-key (true|false) 'false'> <!ATTLIST field null-value (exception|default|none) 'none'> <!ATTLIST field default-fetch-group (true|false) #IMPLIED> <!ATTLIST field embedded (true|false) #IMPLIED> <!ELEMENT array (extension)*> <!ATTLIST array embedded-element (true|false) #IMPLIED> <!ELEMENT collection (extension)*> <!ATTLIST collection element-type CDATA #IMPLIED> <!ATTLIST collection embedded-element (true|false) #IMPLIED> <!ELEMENT map (extension)*> <!ATTLIST map key-type CDATA #IMPLIED> <!ATTLIST map embedded-key (true|false) #IMPLIED> <!ATTLIST map value-type CDATA #IMPLIED> <!ATTLIST map embedded-value (true|false) #IMPLIED> <!ELEMENT extension (extension)*> <!ATTLIST extension vendor-name CDATA #REQUIRED> <!ATTLIST extension key CDATA #IMPLIED> <!ATTLIST extension value CDATA #IMPLIED>
The root element of all metadata documents is the jdo element. The only legal children of the jdo element are package elements. Each package element must specify a name attribute giving the full name of the package it represents.
Example 5.1. Basic Structure of Metadata Documents
<?xml version="1.0"?> <jdo> <package name="org.mag"> ... </package> <package name="org.mag.subscribe"> ... </package> </jdo>
package elements contain one or more class elements, followed by zero or more extension elements. Extensions are used to annotate metadata with vendor-specific information. The extension element may contain nested extension elements, and has three attributes:
vendor-name: The name of the vendor the extension applies to. This attribute is required.
key: The name of the property you are setting with the extension. Each vendor will supply a list of supported properties.
value: The value of the property.
Kodo JDO defines many useful metadata extensions. See the Kodo JDO Reference Guide chapter on metadata extensions for a full list.
Every persistence-capable class in the package named by each package element must be represented by a class element. Before we explore this element in detail, a brief note on how JDO resolves class names is in order.
Several metadata attributes require you to specify class names. The names you give should follow these guidelines:
If the class is in the package named by the current package element, you can give just the class name, without specifying the package. For example, if the current package name is org.mag and the class is org.mag.Magazine, then you can simply write Magazine for the class name.
Similarly, if the class is in java.lang, java.util, or java.math packages, you do not need to specify the package in the class name.
Otherwise, the full class name is required, including package name.
If the class is an inner class, then write it as parent-class$inner-class For example, SubscriptionForm$LineItem.
We now turn our attention back to the class element. This element has the following attributes:
name: The name of the class. This attribute is required.
persistence-capable-superclass: If the superclass of this class is also persistent, and you wish JDO to know about the inheritance structure, then you must name the superclass in this attribute. If the superclass of this class is not persistent or if for some reason you want JDO to treat the superclass as unrelated, you should not specify this attribute.
identity-type: Gives the JDO identity type used by the class. Legal values are application for application identity, datastore for datastore identity, and none. This attribute defaults to a value of application if the objectid-class attribute is specified, and datastore otherwise.
objectid-class: For application identity, the name of the JDO identity class used by this persistent class. To use single field application identity (see Section 4.5.3, “Single Field Identity”), do not specify this attribute. If your persistent subclass uses the same objectid-class as its superclass, you do not have to specify this attribute.
requires-extent: Set this attribute to false if you will never need to query for persistent instances of this class (i.e., if all objects of the class can be obtained through JDO identity lookups or through relations with other objects). Defaults to true.
Example 5.2. Metadata Class Listings
<?xml version="1.0"?> <jdo> <package name="org.mag"> <!-- application identity --> <class name="Magazine" objectid-class="Magazine$ObjectId"> ... </class> <!-- single field identity --> <class name="Article" identity-type="application"> ... </class> <!-- default datastore identity --> <class name="Author"> ... </class> <class name="Address"> ... </class> </package> <package name="org.mag.subscribe"> <class name="Form"> ... </class> <!-- inheritance --> <class name="SubscriptionForm" persistence-capable-superclass="Form"> ... </class> <!-- static inner class --> <class name="SubscriptionForm$LineItem"> ... </class> </package> </jdo>
The class element may contain extension elements and field elements. field elements represent fields declared by the persistence-capable class. These elements are optional; if a field declared in the class is not named by some field element, then its properties are defaulted as explained in the attribute listings below. Thanks to JDO's comprehensive set of defaults, most fields do not need to be listed explicitly. field elements may have the following attributes:
name: The name of the field, as it is declared in the persistence-capable class. This attribute is required.
persistence-modifier: Specifies how JDO should manage the field. Legal values are persistent for persistent fields, transactional for fields that are non-persistent but can be rolled back along with the current transaction, and none. The default value of this attribute is based on the type of the field:
Fields declared static, transient, or final default to none.
Fields of any primitive or primitive wrapper type default to persistent.
Fields of types java.lang.String, java.lang.Number, java.math.BigDecimal, java.math.BigInteger, java.util.Locale, and java.util.Date default to persistent.
Fields of any user-defined persistence-capable type default to persistent.
Arrays of any of the types mentioned so far default to persistent.
Fields of the following container types in the java.util package default to persistent: Collection, Set, List, Map, ArrayList, HashMap, HashSet, Hashtable, LinkedList, TreeMap, TreeSet, Vector.
All other fields default to none.
primary-key: Set this attribute to true if the class uses application identity and this field is a primary key field. Defaults to false.
null-value: Specifies the treatment of null values when the field is written to the data store. Use a value of none if the data store should hold a null value for the field. Use default to write a data store default value instead. Finally, use exception if you want the JDO implementation to throw an exception if the field contains a null value when it is being written to the data store. Defaults to none.
default-fetch-group: Default fetch group fields are managed together as a group for efficiency. They are typically loaded as a block from the data store, and are often written as a block as well. This attribute defaults to true for primitive, primitive wrapper, String, Date, BigDecimal, and BigInteger types. All other types default to false.
embedded: This is a hint to the JDO implementation to store the field as part of the class instance in the data store, rather than as a separate entity. JDO implementations are free to ignore this attribute. Its value defaults to true for primitive, primitive wrapper, Date, BigDecimal, BigInteger, array, collection, and map types. All other types default to false. Embedded objects do not appear in the Extent for their class, and cannot be retrieved by query.
When you mark a relation to another persistence-capable object as embedded, Kodo JDO stores the object in the same table row in the database as the parent object. Kodo even allows recursively embedded objects (a Company has an embedded Address which has an embedded PhoneNumber, for example).
All field elements may contain extension child elements. field elements that represent array, collection, or map fields may also contain a single array, collection, or map child element, respectively. Each of these elements may contain additional extension elements in turn.
The array element has a single attribute, embedded-element. This attribute mirrors the embedded attribute of the class element, but applies to the values stored in each array index.
The collection element also has the embedded-element attribute. Additionally, it declares the element-type attribute. Use this attribute to tell the JDO implementation what class of objects the collection contains. If the element-type is not given, it defaults to java.lang.Object, unless the collection field in the object is defined using Java 5 generics, in which case the type information will default to the generic type information.
map elements define four attributes. They are:
key-type: The class of objects used for map keys. Defaults to java.lang.Object, or to the Java 5 generic type information for the key if available.
embedded-key: Same as the embedded-element element of arrays and collections, but applies to map keys.
value-type: The class of objects used for map values. Defaults to java.lang.Object, or to the Java 5 generic type information for the key if available.
embedded-value: Same as the embedded-element element of arrays and collections, but applies to map values.
That exhausts the metadata document structure. A complete metadata document example is presented below.
Example 5.3. Complete Metadata Document
<?xml version="1.0"?> <!-- Note that all persistence-capable classes must be listed, but --> <!-- very few fields need to be specified --> <jdo> <package name="org.mag"> <class name="Magazine" objectid-class="Magazine$ObjectId"> <field name="isbn" primary-key="true"/> <field name="title" primary-key="true"/> <field name="articles"> <collection element-type="Article"/> </field> </class> <class name="Article" identity-type="application"> <field name="id" primary-key="true"/> <field name="authors"> <map key-type="String" value-type="Author"/> </field> </class> <class name="Author"> <field name="address" embedded="true"/> </class> <class name="Address"/> </package> <package name="org.mag.subscribe"> <class name="Form"/> <class name="SubscriptionForm" persistence-capable-superclass="Form"> <field name="lineItems"> <collection element-type="SubscriptionForm$LineItem"/> <extension vendor-name="kodo" key="inverse-owner" value="form"/> </field> </class> <class name="SubscriptionForm$LineItem"/> </package> </jdo>