3.12 Types of Object Identity
The JDO specification requires that either datastore or application identity be supported (support for both is optional) and support for non-durable identity is optional. Most JDO implementations support datastore identity as their default, and some also support application identity (notably, those that are designed to run on top of a relational database).
3.12.1 Datastore identity
Datastore identity is the simplest form of identity. The JDO object identity of a persistent object is assigned and managed by the JDO implementation, typically in conjunction with the underlying datastore. The identity is orthogonal to the values of any of the fields of a persistent object.
There is nothing an application itself needs to do or provide when using datastore identity other than the Java classes themselves.
Unless there is a specific need otherwise, datastore identity should always be used. It's the simplest and most portable form of JDO object identity, and it is widely supported by most JDO implementations.
3.12.2 Application identity
Application identity is more akin to the concept of a relational primary key. The JDO object identity of a persistent object is determined by the values of certain of its fields.
If using application identity, the application needs to specify which fields are part of the primary key in the JDO metadata for the class and provide a class that can be used by a JDO implementation to represent the persistence-capable class's object identity.
Application identity is particularly useful if using JDO on top of a predefined datastore schema where primary keys have already been defined.
The following code snippet shows how the Author class does not need to change from the original Author class. Regardless of the type of identity being used, the persistence-capable class remains the same:
public class Author { private String name; public Author (String name) { this.name = name; } protected Author () {} public String getName () { return name; } public void setName (String name) { this.name = name; } }
However, the JDO metadata for the class does change. The identity-type attribute needs to be set to "application" and the objectid-class attribute should denote the class that the JDO implementation can use to represent the object identity of a persistent object. Also, the primary-key attribute should be set to "true" for each field of the persistence-capable class that is part of the primary key.
The revised JDO metadata for the Author class in Author.jdo is as follows:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE jdo SYSTEM "jdo.dtd"> <jdo> <package name="com.corejdo.examples.model"> <class name="Author" identity-type="application" objectid-class="AuthorUsingApplicationIdentityKey"> <field name="name" primary-key="true"/> </class> </package> </jdo>
If the package of the object identity class is not specified, it is assumed to be the same as the persistence-capable class itself.
The final requirement when using application identity is to provide the implementation of the object identity class. JDO mandates that this class adhere to the following rules:
-
The class must be public.
-
The class must implement Serializable.
-
The class must have a public no-arg constructor.
-
There must be a public field of the same name and type as each field that is part of the primary key for the persistence-capable class.
-
The equals() and hashCode() methods must use the values of all the primary key fields.
-
The toString() method must return a string representation of the object identity instance.
-
The class must have a constructor that takes a string returned from the toString() method of an object identity instance and constructs an equivalent object identity instance.
The following code snippet taken from AuthorKey.java shows the implementation of the object identity class for the Author persistence-capable class:
import java.io.Serializable; public class AuthorKey implements Serializable { /* * JDO requires that an identity class have a * public field of the same name and type for each of * the primary key fields of the persistence-capable * class. */ public String name; /* * JDO requires a public no-arg constructor */ public AuthorKey () {} /* * JDO requires a public constructor that takes a string. */ public AuthorKey (String oid) { name = oid; } /* * JDO requires that the toString() method return * a string representation of the primary key fields that * can later be used to recreate an identity instance * using the string constructor. */ public String toString() { return name; } /* * JDO requires the equals() method to compare based on * all the primary key fields. */ public Boolean equals(Object obj) { return name.equals( ((AuthorUsingApplicationIdentityKey) obj).name); } /* * JDO requires the hashCode() method to return a * hashcode based on all the primary key fields. */ public int hashCode() { return name.hashCode(); } }
Primary Key Fields
A persistence-capable class can have multiple primary-key fields. The equals() and hashCode() methods on the object identity class must take into account each of the primary-key fields. Also, the toString() method should concatenate all the primary-key fields into a single string, which the string constructor can later tokenize to recreate the identity instance again.
When using application identity, only fields declared in abstract superclasses and the least-derived concrete class in the inheritance hierarchy can be part of the primary key. For example, if a class inherited from the Author class, then it could not provide its own object identity class or set the "primary-key" attribute to "true" for any of its locally declared fields. Instead, it would use the same application identity as defined for the Author class.
If using application identity, a JDO implementation may optionally allow an application to change a persistent object's identity by modifying the values of the primary key fields. If not supported, a JDOUnsupportedOptionException is thrown.
3.12.3 Non-durable identity
Non-durable identity is essentially no identity. The JDO object identity of a persistent object is valid only within the context of a given transaction. If the same persistent object is accessed in a different transaction, it may have a different object identity.
Non-durable identity should be used only when object identity has no relevance, i.e., when there is no need to maintain references between objects. Essentially, it only makes sense to query for objects with non-durable identity.
There are few, if any, JDO implementations that actually support non-durable identity. Its use is limited to a small number of use cases, and as such, most developers can safely ignore non-durable identity.