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 private
, public
, protected
, static
, transient
, final
, and volatile
. But static
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
using the 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.
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 Object
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
Collection
and 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 PersistenceManagerFactory.supportedOptions(
)
.
Table 4-3. Collection interfaces and classes
You use a collection
element
to specify a collection’s characteristics in the metadata. By
default, collection-typed fields are persistent with an Object
element type. You use the collection
element’s element-type
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
necessary.
A 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 Object
. You
can use the map
element’s
key-type
and
value-type
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 $
marker.
We encourage you to specify the types of collection elements
and the keys and values of Map
s.
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
static
or 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 final
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)
Interface references
Object
references
Though interface and Object
references are transient by default, you can still declare them to be
persistent in the metadata.
Java’s transient
modifier
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
the field
element’s persistence-modifier
attribute to specify
whether a field is persistent, by giving it one of the following
values:
- "
persistent
" The field is persistent.
- "
none
" The field is transient.
- "
transactional
" 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
Chapter 12.
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.
Consider class E
, contained
in the inheritance hierarchy depicted in Figure 4-1. E
is a persistent class that extends the
transient class B
. B
extends the persistent class A
. For any instance of B
, E
,
or any class extending E
, the
fields of 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 persistence-modifier
attribute.
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.
Get Java Data Objects now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.