4.3. Restrictions on Persistent Classes

4.3.1. Inheritance
4.3.2. Persistent Fields
4.3.3. Conclusions

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. 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 use the same identity class. We will cover JDO identity shortly.

4.3.2. Persistent Fields

JDO manages the state of all persistent fields. Before you access a field, JDO makes sure that it has been loaded from the data store. When you set a field, JDO 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 includes 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 for persistent fields:

  • All primitives (int, float, byte, etc)

  • All primitive wrappers (java.lang.Integer, java.lang.Float, java.lang.Byte, etc)

  • java.lang.String

  • java.math.BigInteger

  • java.math.BigDecimal

  • java.util.Locale

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 type:

  • java.util.Date

  • java.util.HashSet

[Note]Note

Most JDO implementations support many other mutable field types as well. Kodo JDO supports the following:

  • java.util.List

  • java.util.ArrayList

  • java.util.LinkedList

  • java.util.Vector

  • java.util.Set

  • java.util.SortedSet

  • java.util.TreeSet

  • java.util.Map

  • java.util.HashMap

  • java.util.SortedMap

  • java.util.TreeMap

  • java.util.Hashtable

  • java.util.Properties

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

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 data store 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 explicitly tell the JDO implementation you have changed the array field; this is referred to as "dirtying" the field. Dirtying is accomplished through the JDOHelper's makeDirty method.

Example 4.2. Accessing Mutable Persistent Fields

/**
 * Example demonstrating the use of mutable persistent fields in JDO.
 * Assume Person is a persistent class.
 */
public void addChild (Person parent, Person child)
{
    // can modify most mutable types directly; JDO tracks
    // the modifications for you
    Date lastUp = parent.getLastUpdated ();
    lastUp.setTime (System.currentTimeMillis ());
    Collection children = parent.getChildren ();
    children.add (child);
    child.setParent (parent);

    // arrays need explicit dirtying if they are modified,
    // but not if the field is reset
    parent.setObjectArray (new Object[0]);
    child.getObjectArray ()[0] = parent;
    JDOHelper.makeDirty (child, "objectArray");
}

As the 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 and collections of user-defined persistent classes as persistent field types. The exact collection classes you can use to hold persistent relations will depend on which mutable field types the implementation supports. Some JDO implementations may also allow map fields in which the keys, values, or both are relations to other persistent objects. Again, the exact types of maps allowed depend on the implementation's mutable field type support.

[Note]Note

Kodo JDO supports user-defined persistent classes for map values, but it only allows immutable types for map keys.

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 the information on these fields is so limited, 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]Note

Kodo JDO supports persistent fields of an unknown type by serializing the field value and storing it as a sequence of bytes.

4.3.3. Conclusions

This section detailed all of the restrictions JDO places on persistent classes. While it may seem like a lot of information was presented, 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 presents a powerful JDO feature that is particularly useful for this purpose.