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 numeric identity.
		
JDO introduces another form of object identity, called JDO identity. JDO identity tests whether two persistent objects represent the same state in the datastore.
		
		
		
		
	 	The JDO identity of each persistent instance is encapsulated in its 
		JDO identity object.	You can obtain the JDO 
		identity object for a persistent instance through the 
		
		JDOHelper's
		getObjectId method.  If two JDO identity
		objects compare equal using the equals
		method, then the two persistent objects represent the
		same state in the datastore. 
		
Example 4.4. JDO Identity Objects
/**
 * This method tests whether the given persistent objects represent the
 * same datastore record.  It returns false if either argument is not
 * a persistent object.
 */
public boolean persistentEquals (Object obj1, Object obj2)
{
    Object jdoId1 = JDOHelper.getObjectId (obj1);
    Object jdoId2 = JDOHelper.getObjectId (obj2);
    return jdoId1 != null && jdoId1.equals (jdoId2);
}
		
		
		If you are dealing with a single 
		PersistenceManager, then there is
		an even easier way to test whether two persistent object references
		represent the same state in the datastore: the 
		== operator.  JDO requires that 
		each PersistenceManager maintain only one
		JVM object to represent each unique datastore record.  Thus, JDO
		identity is equivalent to numeric 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 datastore?  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. All persistent classes in an inheritance tree must use the same form of JDO identity.
![]()  | Note | 
|---|---|
Kodo supports both datastore and application identity.  | 
Datastore identity is managed by the JDO implementation. It is independent of the values of your persistent fields. You have no control over what class is used for JDO identity objects, and limited control over 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 implement the toString
					 method such that passing the result to 
					PersistenceManager.newObjectIdInstance
					 creates a new JDO identity object that 
					compares equal to the instance the string was obtained 
					from. 
					
			The last criterion is particularly important.  As you
			will see in the chapter on 
			PersistenceManagers, it allows you to
			store the identity of a persistent instance as a 
			string, then later recreate the identity object and
			retrieve the corresponding persistent instance.
			
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. These fields are called primary key fields. Each object's primary key field values must be unique among all other objects of the same type.
			When using application identity, the equals
			and hashCode methods of the 
			persistence-capable class must depend on all of the primary key 
			fields.
			
![]()  | Note | 
|---|---|
Kodo does not depend upon this behavior. However, some JDO implementations do, so you should implement it if portability is a concern.  | 
If your class has only one primary key field, you can use single field identity to simplify working with application identity (see Section 4.5.3, “Single Field Identity”). Otherwise, you must supply an application identity class to use for JDO identity objects. Your application identity class must meet all of the criteria listed for datastore identity classes. It must also obey the following requirements:
					The class must have a string constructor, or a constructor
					that takes a Class, String
					 argument pair.  The optional 
					Class argument is the target persistent class,
					and the string is the result of 
					toString on another 
					identity instance of the same type.
					
The names of the non-static fields of the class must include the names of the primary key fields of the corresponding persistent 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 persistent class.
					
					If the class is an inner class, it must be
					static.
					
All classes related by inheritance must use the same application identity class, or else each class must have its own application identity class whose inheritance hierarchy mirrors the inheritance hierarchy of the owning persistent classes (see Section 4.5.2.1, “Application Identity Hierarchies”).
					Primary key fields must be primitives, primitive wrappers,
					Strings, or 
					Dates. Notably, other persistent instances can
					not be used as primary key fields.
					
![]()  | Note | 
|---|---|
				For legacy schemas with binary primary key columns, Kodo
				also supports using primary key fields of type 
				  | 
			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 persistent class with the JVM. This is typically accomplished with a static block in the application identity class code, as the example below illustrates. 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 | 
|---|---|
				Though you may still create application identity classes by
				hand, Kodo provides the   | 
Example 4.5. Application Identity Class
/**
 * Persistent class using application identity.
 */
public class Magazine
{
    private String isbn;    // primary key field
    private String title;   // primary key field
    /**
     * Equality must be implemented in terms of primary key field
     * equality, and must use instanceof rather than comparing 
     * classes directly.
     */
    public boolean equals (Object other)
    {
        if (other == this)
            return true;
        if (!(other instanceof Magazine))
            return false;
        Magazine mag = (Magazine) other;
        return (isbn == mag.isbn
            || (isbn != null && isbn.equals (mag.isbn)))
            && (title == mag.title
            || (title != null && title.equals (mag.title)));
    }
     
    /**
     * Hashcode must also depend on primary key values.
     */
    public int hashCode ()
    {
        return ((isbn == null) ? 0 : isbn.hashCode ())
            ^ ((title == null) ? 0 : title.hashCode ());
    }
    // rest of fields and methods omitted
    /**
     * Application identity class for Magazine.
     */
    public static class MagazineId
    {
        static
        {
            // register Magazine with the JVM
            try { Class.forName ("Magazine") } catch (Exception e) {}
        }
    
        // each primary key field in the Magazine class must have a
        // corresponding public field in the identity class
        public String isbn;
        public String title;
        /**
         * Default constructor requirement.
         */
        public MagazineId ()
        {
        }
    
        /**
         * String constructor requirement.
         */
        public MagazineId (String str)
        {
            int idx = str.indexOf (':');
            isbn = str.substring (0, idx);
            title = str.substring (idx + 1);
        }
    
        /**
         * toString must return a string parsable by the string constructor.
         */
        public String toString ()
        {
            return isbn + ":" + title;
        }
    
        /**
         * Equality must be implemented in terms of primary key field
         * equality, and must use instanceof rather than comparing 
         * classes directly (some JDO implementations may subclass JDO
         * identity class).
         */
        public boolean equals (Object other)
        {
            if (other == this)
                return true;
            if (!(other instanceof MagazineId))
                return false;
    
            MagazineId mi = (MagazineId) other;
            return (isbn == mi.isbn
                || (isbn != null && isbn.equals (mi.isbn)))
                && (title == mi.title
                || (title != null && title.equals (mi.title)));
        }
     
        /**
         * Hashcode must also depend on primary key values.
         */
        public int hashCode ()
        {
            return ((isbn == null) ? 0 : isbn.hashCode ())
                ^ ((title == null) ? 0 : title.hashCode ());
        } 
    }
}

An alternative to having a single application identity class for an entire inheritance hierarchy is to have one application identity class per level in the inheritance hierarchy. The requirements for using a hierarchy of application identity classes are as follows:
						The inheritance hierarchy of application identity 
						classes must exactly mirror the hierarchy of the
						persistent classes that they identify. In the example
						pictured above, abstract class
						Person is extended by abstract
						class Employee, which is extended
						by non-abstract class 
						FullTimeEmployee, which is extended by
						non-abstract class Manager.
						The corresponding identity classes, then, are
						an abstract PersonId class,
						extended by an abstract 
						EmployeeId class, extended by a 
						non-abstract FullTimeEmployeeId
						class, extended by a non-abstract
						ManagerId class.
						
						Subclasses in the application identity hierarchy
						may define additional primary key fields until
						the hierarchy becomes non-abstract. In the
						aforementioned example, Person
						defines a primary key field ssn,
						Employee defines additional 
						primary key field userName, and 
						FullTimeEmployee adds a final
						primary key field, empId.  
						However, Manager may not define 
						any additional primary key fields, since it is a 
						subclass of a non-abstract class.  The hierarchy of
						identity classes, of course, must match the primary key
						field definitions of the persistent class hierarchy.
						
						It is not necessary for each abstract class to declare 
						primary key fields.  In the previous example, the 
						abstract Person and 
						Employee classes could declare 
						no primary key fields, and the first concrete subclass 
						FullTimeEmployee could define 
						one or more primary key fields.
						
						All subclasses of a concrete identity class must
						be equals and 
						hashCode-compatible with the concrete
						superclass.  This means that in our example, a
						ManagerId instance and a
						FullTimeEmployeeId instance 
						with the same primary key field values should have the
						same hash code, and should compare equal to each other
						using the equals method of
						either one.  In practice, this requirement reduces to
						the following coding practices:  
						
								Use instanceof instead of
								comparing Class objects
								in the equals methods
								of your identity classes.
								
								An identity class that extends another 
								non-abstract identity class should not override
								equals or 
								hashCode.
								

			
			Single field identity is a subset of application identity.  When
			you have only one primary key field, you can choose to use one
			of JDO's built-in single field identity classes instead of coding
			your own application identity class.  All single field identity
			classes extend 
			
			
			javax.jdo.identity.SingleFieldIdentity.
			This base type defines the following methods:
			
public Object getKeyAsObject ()
			Returns the primary key value as an object.  Each 
			SingleFieldIdentity subclass also defines a
			getKey method to return the primary key
			in its primitive form.
			
public Class getTargetClass ()
			The target class of a single field identity object is the persistent
			class to which the identity object corresponds.  Note that the
			target class is not part of the serialized state of a 
			SingleFieldIdentity instance.  After an
			instance has been deserialized, calls to this method return
			null.
			
public String getTargetClassName ()
Returns the name of the target class. This method returns the correct value even after a single field identity object has been deserialized.
The following list enumerates the primary key field types supported by single field identity, and the built-in identity class for each type:
					
					
					byte, 
					java.lang.Byte:
					
					javax.jdo.identity.ByteIdentity
					
					
					
					
					char, 
					java.lang.Character:
					
					javax.jdo.identity.CharIdentity
					
					
					
					
					int, 
					java.lang.Integer:
					
					javax.jdo.identity.IntIdentity
					
					
					
					
					long, 
					java.lang.Long:
					
					javax.jdo.identity.LongIdentity
					
					
					
					
					short, 
					java.lang.Short:
					
					javax.jdo.identity.ShortIdentity
					
					
					
					
					java.lang.String:
					
					javax.jdo.identity.StringIdentity