Fields contain the state of an instance. JDO provides for the
access, management, and storage of an instance’s fields in a datastore.
All of Java’s field type categories are supported: primitive types,
reference types, and interface types. JDO also supports all of Java’s
field modifiers, including
final , and
final fields cannot be persistent, as
we will discuss later in this chapter.
As we explained earlier, you can have both transient and persistent instances of a persistent class. The individual fields of a persistent class can also be transient or persistent for all of the class’s persistent instances. A field’s type and modifiers determine whether it is persistent or transient, by default. You can override the default persistence of a field in the metadata. We cover transient fields later in this chapter.
You can specify persistence-related information about a field by
field metadata element. Its required
name attribute should have the name of the field in the Java
class declaration. It has attributes to control the field’s persistence
and the type of its elements if it is a collection. We cover these
attributes later in this chapter. If the class uses application
identity, one or more fields need to indicate they are a primary-key
field; Chapter 10 covers this in
detail. Chapter 12 addresses
advanced field-management facilities enabled by the remaining
field element attributes.
You do not need to provide metadata for every field in a class. Default values are assumed for any fields that lack metadata declarations. These default values usually provide the behavior that you need. So, in many circumstances, you do not need to provide field metadata.
You cannot make many system-defined classes persistent, nor can you have a field of a system-defined class. Table 4-2 lists the system-defined types in the Java language environment that JDO implementations do support.
Table 4-2. Supported field types
You can declare a field to refer to a persistent class instance. In addition, you can use Java’s polymorphism to declare a field that refers to a base class and have it reference a subclass instance. You should be accustomed to using polymorphic references in your object models. Object databases have supported them for many years, but this modeling capability has not been available in relational database schemas and interfaces. The JDO implementation is responsible for implementing such polymorphic references on top of the underlying datastore, including a relational datastore. If a field is declared to be a reference to a transient class, and you assign a reference to an instance of a subclass that is persistent, the instance is not stored, because the field’s declared type is not persistent.
You can use fields of
and interface types. You can assign a reference to an instance of any
class to an
Object field, and an
instance of any class implementing an interface can be assigned to an
interface. You can also use interface inheritance in your model.
Interface fields are transient by default, so you need to declare the
field persistent explicitly in your metadata. We recommend you assign
only instances of types supported by JDO to
Object and interface fields. If an
implementation restricts the type of instance that can be assigned to
such a field, it will throw a
ClassCastException when an incorrect assignment is made.
You can use a collection to represent multiple values of a given
type or to represent to-many relationships among
classes in an object model. Table 4-3 lists the
Set collection interfaces and the
HashSet collection class from the
java.util package that are available in
all JDO implementations. Additional collection classes that are
optional in JDO are listed with their associated option property
name. If an implementation supports the collection, it will return
the collection’s associated property string when you call
Table 4-3. Collection interfaces and classes
You use a
to specify a collection’s characteristics in the metadata. By
default, collection-typed fields are persistent with an
Object element type. You use the
attribute to specify the collection’s element type. Specifying the
element type is not required, but we recommend you specify it. The
type name you specify uses Java’s rules for naming: if no package is
provided in the name, the package is assumed to be the same package
as the enclosing persistent class in the metadata. Inner classes are
identified with the
$ marker. At
some point, the Java language may allow you to specify a
collection’s element type directly when you declare the collection
in your Java code, in which case this metadata will no longer be
Map maintains a set of
key-value pairs; both the key and value have a type. You use a
map element to
specify the characteristics of map’s keys and values in the
metadata. By default, map-typed fields are persistent and their key
and value types are
can use the
attributes to specify a more specific type. As with collections,
Java’s rules for naming apply if the package is not provided, and
inner classes can be identified with the
We encourage you to specify the types of collection elements
and the keys and values of
Some implementations use a far less efficient means of accessing the
elements if you do not specify the type.
Array fields are optional in JDO. The JDO
javax.jdo.option.Array option property indicates whether an implementation
supports them. You should not share a specific array among several
persistent instances. The JDO specification does not state whether
multidimensional arrays are supported. Support for multidimensional
arrays varies among implementations.
A field’s type and modifiers in a Java class declaration determine whether it is persistent by default. You can also override the default persistence of a field by declaring it as persistent or transient in the metadata.
Some fields cannot be persistent. A field declared in Java to be
final is always transient. A
static field has only one value; the field is associated with
the class itself and shared by all instances. A
final field has one value per instance. But a
final field is initialized once by the
constructor and its value can never be changed once the instance is
constructed. Each constructor may initialize a final field
differently. JDO implementations call the no-arg constructor to create an instance you access from
the datastore. The field values from the datastore are set after the
no-arg constructor is called. Thus, it is not possible for the JDO
implementation to manage a
field’s persistent state in memory.
Fields of the following types are persistent by default:
Fields of the following types are transient by default:
References to transient application classes
References to system classes defined in JDK packages (unless supported in JDO)
Though interface and
references are transient by default, you can still declare them to be
persistent in the metadata.
is used to specify whether a field and the object graph it may
reference should be serialized. By default, a field declared
transient in a Java class declaration is transient from a JDO
perspective, but you can override this in the metadata. You can use
persistence-modifier attribute to specify
whether a field is persistent, by giving it one of the following
The field is persistent.
The field is transient.
The field is a transactional field, which is a transient field that has transactional behavior. Chapter 12 covers transactional fields.
So, a transient field in Java (specified via the
transient modifier in the Java class
declaration) is distinct from a transient field in JDO. If you
declare a field in a Java class declaration with the
transient modifier, it can be transient or
persistent in JDO; and if a field does not have the Java
transient modifier, it can also be
transient or persistent, depending on the field’s
persistence-modifier attribute. If you do
not specify the
persistence-modifier attribute in the
metadata, its default value is based on the field’s type and
modifiers, as defined in the Java class declaration.
There is no restriction on the type of a transient field. Transient fields are managed entirely
by the application, not by the JDO implementation. A JDO
implementation calls the no-arg constructor to instantiate an instance when the
application accesses it from the datastore. You can define the
default constructor to initialize transient and
final fields. The
InstanceCallbacks interface can also be
used to manage the state of transient fields; this is covered in
Persistent and transactional fields are also referred to as managed fields , since the JDO implementation manages their state. Figure 4-5 illustrates which kinds of fields are managed and which are transient.
A class’s metadata cannot specify characteristics for any field it inherits from a superclass, so a subclass cannot alter the persistence of an inherited field. Therefore, a field identified as persistent by the class’s metadata is persistent in all subclasses; if it is transactional, it is transactional in all subclasses, and if it is transient, it is transient in all subclasses.
in the inheritance hierarchy depicted in Figure 4-1.
E is a persistent class that extends the
B extends the persistent class
A. For any instance of
or any class extending
B are transient, and
you cannot make them persistent in the metadata unless you make
B a persistent class.
Of course, you can declare a class with a field that has the
same name as a field in a superclass. Even though the field name is
the same, these are two different fields. Therefore, you can have
different values for their
Now we can present the complete metadata for our Media Mania model, including the additional metadata we have covered:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN" "http://java.sun.com/dtd/jdo_1_0.dtd"> <jdo> <package name="com.mediamania.content" > <class name="Studio" > <field name="content" > <collection element-type="MediaContent"/> </field> </class> <class name="MediaContent" > <field name="mediaItems" > <collection element-type="com.mediamania.store.MediaItems"/> </field> </class> <class name="Movie" persistence-capable-superclass="MediaContent"> <field name="cast" > <collection element-type="Role"/> </field> </class> <class name="MediaPerson" > <field name="actingRoles" > <collection element-type="Role"/> </field> <field name="moviesDirected" > <collection element-type="Movie"/> </field> </class> <class name="Game" persistence-capable-superclass="MediaContent" /> <class name="Role" /> </package> <package name="com.mediamania.store" > <class name="MediaItem" > <field name="rentalItems"> <collection element-type="RentalItem"/> </field> </class> <class name="RentalItem"/> <class name="Customer" > <field name="currentRentals"> <collection element-type="Rental"/> </field> <field name="transactionHistory"> <collection element-type="Transaction"/> </field> </class> <class name="Address" /> <class name="Transaction" /> <class name="Purchase" persistence-capable-superclass="Transaction"/> <class name="Rental" persistence-capable-superclass="Transaction"/> <class name="RentalCode" /> </package> </jdo>
We specified each collection’s element type in the model. The
mediaItems field in
MediaContent is the only collection whose
element type is a class in a different package, so we specified the
full package name.