4.5. JDO Identity

4.5.1. Datastore Identity
4.5.2. Application Identity

Java recognizes two forms of object identity: numeric identity and qualitative identity. If two references are numerically identical, then they refer to the same JVM instance in memory. You can test for this using the == operator. Qualitative identity, on the other hand, relies on some user-defined criteria to determine whether two objects are "equal". You test for qualitative identity using the equals method. By default, this method simply relies on numerical identity.

JDO introduces another form of object identity, called JDO identity. JDO identity tests whether two persistent objects represent the same state in the data store.

You can obtain the JDO identity object from a persistent instance through the JDOHelper's getObjectId method. If two JDO identity objects compare equal using the equals method, then the two corresponding persistent objects represent the same state in the data store.

If you are dealing with a single PersistenceManager, then there is an even easier way to test whether two persistent object references represent that same state in the data store: use the == operator. JDO requires that each PersistenceManager maintain only one JVM object to represent each unique data store record. Thus, JDO identity is equivalent to numerical identity within a PersistenceManager's cache of managed objects. This is referred to as the uniqueness requirement.

The uniqueness requirement is extremely important -- without it, it would be impossible to maintain data integrity. Think of what could happen if two different objects of the same PersistenceManager were allowed to represent the same persistent data. If you made different modifications to each of these objects, which set of changes should be written to the data store? How would your application logic handle seeing two different "versions" of the same data? Thanks to the uniqueness requirement, these questions do not have to be answered.

There are three types of JDO identity, but only two of them are important to most applications: datastore identity and application identity. The majority of JDO implementations support datastore identity at a minimum; many support application identity as well.

[Note]Note

Kodo JDO supports both datastore and application identity.

4.5.1. Datastore Identity

Datastore identity is managed by the JDO implementation. It is independent of the values of your persistent fields. You have no say over what identity class is used or what data is used to create identity values. The only requirement placed on JDO vendors implementing datastore identity is that the class they use for JDO identity objects meets the following criteria:

  • The class must be public.

  • The class must be serializable.

  • All non-static fields of the class must be public and serializable.

  • The class must have a public no-args constructor.

  • The class must have a public String constructor. It must override the toString method to return a string that can be used by this constructor to create a new JDO identity object that compares equal to the instance the string was obtained from.

The last criterion listed is particularly important. As you will see in the chapter on PersistenceManagers, it allows you to store the identity object for a persistent instance as a string, then later recreate the identity object and retrieve the corresponding persistent instance.

4.5.2. Application Identity

Application identity is managed by you, the developer. Under application identity, the values of one or more persistent fields in an object determine its JDO identity. The fields whose values make up the object's identity are called primary key fields. Each object's primary key fields must be unique among all other objects of the same type.

When using application identity, it is up to you to supply the class used for JDO identity objects. This application identity class must meet all of the criteria listed for datastore identity classes. It must also obey the following requirements:

  • The names of the non-static fields of the class must include the names of the primary key fields of the corresponding persistence-capable class, and the field types must be identical.

  • The equals and hashCode methods of the class must use the values of all fields corresponding to primary key fields in the persistence-capable class.

  • If the class is an inner class, it must be static.

  • All classes related by inheritance must use the same application identity class.

  • Each inheritance tree must use a unique application identity class.

These criteria allow you to construct an application identity object from either the values of the primary key fields of a persistent instance, or from a string produced by the toString method of another identity object.

Though it is not a requirement, you should also use your application identity class to register the corresponding persitence capable class with the JVM. This is typically accomplished with a static block in the application identity class code:

/**
 *  Application identity class for persistence capable class Magazine.
 */
public class MagazineId
{
    static
    {
        // register Magazine with the JVM
        Class c = Magazine.class;
    }

    // rest of code...
}

This registration process is a workaround for a quirk in JDO's persistent type registration system whereby some by-id lookups might fail if the type being looked up hasn't been used yet in your application.

[Note]Note

Though you may still create application identity classes by hand, Kodo JDO provides the com.solarmetric.kodo.enhance.ApplicationIdTool to automatically generate application identity classes that meet the above requirements.