4.3. Restrictions on Persistent Classes

There are very few restrictions placed on persistent classes.
Still, it never hurts to familiarize yourself with exactly what
JDO does and does not support.

4.3.1. Default or No-Arg Constructor

The JDO specification requires that all persistence-capable
classes must have a no-arg constructor. This constructor
may be private. Because the compiler automatically
creates a default no-arg constructor when no other constructor
is defined, only classes that define constructors must also
include a no-arg constructor.

Note

Kodo's enhancer will automatically add a protected no-arg
constructor to your class when required. Therefore, this
restriction does not apply under Kodo.

4.3.2. Inheritance

JDO fully supports inheritance in persistent classes. It allows
persistent classes to inherit from non-persistent classes,
persistent classes to inherit from other persistent classes,
and non-persistent classes to inherit from persistent classes.
It is even possible to form inheritance hierarchies in which
persistence skips generations. There are, however, a few
important limitations:

Persistent classes cannot inherit from certain
natively-implemented system classes such as
java.net.Socket and
java.lang.Thread.

If a persistent class inherits from a non-persistent
class, the fields of the non-persistent superclass
cannot be persisted.

All classes in an inheritance tree must use the same
JDO identity type. If they use application
identity, they must either use the same identity
class, or else they must each declare that they use
separate identity classes whose inheritance hierarchy
exactly mirrors the inheritance hierarchy of the persistent
class hierarchy. We cover JDO identity in
Section 4.5, “JDO Identity”.

4.3.3. Persistent Fields

JDO manages the state of all persistent fields. Before you
access a field, the JDO runtime makes sure that it has been loaded
from the datastore. When you set a field, the runtime records that
it has changed so that the new value will be persisted. This allows
you to treat the field in exactly the same way you treat any
other field - another aspect of JDO's transparent
persistence.

JDO does not support static or final fields. It does, however,
include built-in support for most common field types.
These types can be roughly divided into three categories:
immutable types, mutable types, and relations.

Immutable types, once created, cannot be
changed. The only way to alter a persistent field
of an immutable type is to assign a new value to the field.
JDO supports the following immutable types:

Persistent fields of mutable types
can be altered without assigning the field a new value.
Mutable types can be modified directly through their own
methods. The JDO specification requires that
implementations support the following mutable field types:

java.util.Date

java.util.Collection

java.util.HashSet

java.util.Map

java.util.HashMap

java.util.Hashtable

Collection and map types may be parameterized.

Most implementations do not allow you to persist nested mutable
types, such as Collections of
Maps.

Note

Kodo supports all JDK 1.2 Set,
List, and Map
types,
java.util.Calendar,
java.sql.Date,
java.sql.Time,
java.sql.Timestamp, enums, and many
other mutable and immutable field types.
Kodo also allows you to plug in support for custom types.

Most JDO implementations support mutable fields by transparently
replacing the field value with an instance of a special
subclass of the field's declared type. For example, if
your persistent object has a field containing a
java.util.Date, the JDO implementation
will transparently replace the value of that field at runtime
with some vendor-specific Date subclass
-- call it JDODate. The job of this
subclass is to track modifications to the field. Thus the
JDODate class will override all
mutator methods of Date to notify the JDO
implementation that the field's value has been changed. The
JDO implementation then knows to write the field's new value
to the datastore at the next opportunity.

Of course, when you develop and use persistent classes,
this is all transparent. You continue
to use the standard methods of mutable fields as you
normally would. It is important to know how support
for mutable fields is implemented, however, in order to
understand why JDO has such trouble with arrays. JDO
allows you to use persistent array fields, and it automatically
detects when these fields are assigned a new array value or set
to null. Because arrays cannot be
subclassed, however, JDO cannot detect when new values are
written to array indexes. If you set an index of a persistent
array, you must either reset the array field, or explicitly tell
the JDO implementation you have changed it; this is
referred to as dirtying the field. Dirtying
is accomplished through the JDOHelper's
makeDirty method.

As the parent-child example above illustrates, JDO supports
relations between persistent objects in addition to the standard
Java types covered so far. All JDO implementations should allow
user-defined persistent classes as well as collections and maps
of user-defined persistent classes as persistent field types. The
exact collection and map types you can use to hold persistent
relations will depend on which mutable field types the
implementation supports.

Most JDO implementations also have some support for fields
whose concrete class is not known. Fields declared as type
java.lang.Object or as a user-defined
interface type fall into this category. Because these fields are
so general, though, there may be limitations
placed on them. For example, they may be impossible to query,
and loading and/or storing them may be inefficient.

Note

Kodo supports user-defined persistent objects as elements
of any of the supported collection types. It also supports
user-defined persistent objects as keys, values, or both in
any supported map type.

Kodo supports persistent
java.lang.Object fields by serializing
the field value and storing it as a sequence of bytes. It
supports persistent interface fields by storing the object id
of the instance stored in the field, then re-fetching
the corresponding object when the field is loaded. Collections
and maps where the element/key/value type is
java.lang.Object or an interface are
fully supported as well.

4.3.4. Conclusions

This section detailed all of the restrictions JDO places on
persistent classes. While it may seem like we presented a lot of
information, you will seldom find yourself hindered by these
restrictions in practice. Additionally, there are often ways
of using JDO's other features to circumvent any limitations
you run into. The next section explores a powerful JDO feature
that is particularly useful for this purpose.