JPOX
JPOX
 JPOX Version 1.0
Configuration | Tutorials | Worked Examples | Developer
Obtaining JPOX
JPOX Preparation
JPOX Runtime
Primary Key Classes

With application identity you are taking control of the specification of id's to JPOX. Application identity requires a primary key class, and each persistent capable class may define a different class for its primary key, and different persistent capable classes can use the same primary key class, as appropriate. To specify that a class is to use application identity, you add the following to the MetaData for the class.

<class name="MyClass" identity-type="application" objectid-class="MyIdClass">
    <field name="myPrimaryKeyField" primary-key="true">
...
</class>
            

That is, specifying the "identity-type" and "objectid-class". The "objectid-class" is the class defining the identity for this class. You then need to define the primary key class.

Rules for Primary Key classes

If you wish to use application identity you must define a Primary Key class. You can't use classes like java.lang.String, or java.lang.Long directly. You must follow these rules when defining your primary key class.

  • the Primary Key class must be public
  • the Primary Key class must implement Serializable
  • the Primary Key class must have a public no-arg constructor, which might be the default constructor
  • the field types of all non-static fields in the Primary Key class must be serializable, and are recommended to be primitive, String, Date, or Number types
  • all serializable non-static fields in the Primary Key class must be public
  • the names of the non-static fields in the Primary Key class must include the names of the primary key fields in the JDO class, and the types of the common fields must be identical
  • the equals() and hashCode() methods of the Primary Key class must use the value(s) of all the fields corresponding to the primary key fields in the JDO class
  • if the Primary Key class is an inner class, it must be static
  • the Primary Key class must override the toString() method defined in Object, and return a String that can be used as the parameter of a constructor
  • the Primary Key class must provide a String constructor that returns an instance that compares equal to an instance that returned that String by the toString() method.
  • the Primary Key class must be only used within a single inheritence tree.
Primary Key Example - Single Field

Here's an example of a simple (single field) primary key class

import java.io.Serializable;
 
public class SimpleIdKey implements Serializable
{
    public String myPrimaryKeyField;

    /**
     *  Default constructor.
     */
    public SimpleIdKey () {}

    /**
     *  String constructor.
     */
    public SimpleIdKey (String value) 
    {
        StringTokenizer token = new StringTokenizer (value, "::");
        //className
        token.nextToken ();
        //myPrimaryKeyField
        myPrimaryKeyField = token.nextToken ();
    }

    /**
     *  Implementation of equals method.
     */
    public boolean equals (Object object)
    {
        if (this == object)
        {
            return true;
        }
        if (!(object instanceof SimpleIdKey))
        {
            return false;
        }

        SimpleIdKey other=(SimpleIdKey)object;
        return this.myPrimaryKeyField.equals(other.myPrimaryKeyField);
    }

    /**
     *  Implementation of hashCode method that supports the
     *  equals-hashCode contract.
     */
    public int hashCode ()
    {
        return this.myPrimaryKeyField.hashCode();
    }

    public String toString ()
    {
        return this.getClass().getName() + "::" + this.myPrimaryKeyField;
    }
}
                
Primary Key Example - Multiple Field

Here's an example of a composite (multiple field) primary key class

public class ComposedIdKey implements Serializable
{
    public String field1;
    public String field2;

    /**
     *  Default constructor.
     */
    public ComposedIdKey ()
    {
    }

    /**
     * String constructor.
     */
    public ComposedIdKey(String value) 
    {
        StringTokenizer token = new StringTokenizer (value, "::");
        //className
        token.nextToken ();
        //field1
        this.field1 = token.nextToken ();
        //field2
        this.field2 = token.nextToken ();
    }

    /**
     * Implementation of equals method.
     */
    public boolean equals(Object obj)
    {
        if (obj == this)
        {
            return true;
        }
        if (!(obj instanceof ComposedIdKey))
        {
            return false;
        }
        ComposedIdKey c=(ComposedIdKey)obj;

        return field1.equals(c.field1) && field2.equals(c.field2);
    }

    /**
     *  Implementation of hashCode method that supports the
     *  equals-hashCode contract.
     */
    public int hashCode ()
    {
        return this.field1.hashCode() ^ this.field2.hashCode();
    }

    /**
     *  Implementation of toString that outputs this object id's PK values.
     */
    public String toString ()
    {
        return this.getClass().getName() + "::"  + this.field1 + "::" + this.field2;
    }
}