Chapter 4. PersistenceCapable

4.1. Enhancers
4.2. Persistence-Capable vs. Persistence-Aware
4.3. Restrictions on Persistent Classes
4.3.1. Inheritance
4.3.2. Persistent Fields
4.3.3. Conclusions
4.4. InstanceCallbacks
4.5. JDO Identity
4.5.1. Datastore Identity
4.5.2. Application Identity
4.6. Conclusions

All user-defined persistent classes implement the javax.jdo.spi.PersistenceCapable interface. This interface contains many complex methods that enable the JDO implementation to manage the persistent fields of class instances. Fortunately, you do not have to implement this interface yourself in order to create persistent classes. In fact, writing a persistent class in JDO is usually no different than writing any other class. There are no special parent classes to extend from, field types to use, or methods to write. This is one important way in which JDO makes persistence completely transparent to you, the developer.

Example 4.1. PersistenceCapable Class

package org.mag;

/**
 * Example persistent class.  Notice that it looks exactly like any other
 * class.  JDO makes writing persistent classes completely transparent.
 */
public class Magazine
{
    private String    isbn;
    private String    title;
    private Set       articles = new HashSet ();
    private Date      copyright;
    private Company   publisher;

    public Magazine (String title, String isbn)
    {
        this.title = title;
        this.isbn = isbn;
    }

    public void publish (Company publisher, Date copyright)
    {
        if (copyright == null)
            copyright = new Date ();

        this.publisher = publisher;
        publisher.addMagazine (this);
        this.copyright = copyright;
    }

    public void addArticle (Article article)
    {
        articles.add (article);
    }

    // etc...
}

4.1. Enhancers

In order to shield you from the intricacies of the PersistenceCapable interface, most JDO implementations provide an enhancer. An enhancer is a tool that automatically adds code to your persistent classes after you have written them. Enhancers generally come in two forms: source enhancers and bytecode enhancers.

Source enhancers change the source code in the .java files defining your classes to implement the PersistenceCapable interface. This approach has the advantage of letting you see the changes that are made to your classes; however, it has several disadvantages as well:

  • You must have access to the source code of all of the classes you wish to enhance.

  • If you use a source version control system such as CVS, you must be careful to only commit the unenhanced versions of your source files.

  • Parsing and enhancing source files is relatively slow.

  • During debugging, the line numbers reported in your stack traces will not correspond to the correct lines in your original source files.

Bytecode enhancers, on the other hand, operate on your .class files. They post-process the bytecode generated by your Java compiler, adding the necessary fields and methods to implement the PersistenceCapable interface. Bytecode enhancers overcome the difficulties associated with source enhancers:

  • You do not need access to the source files of the classes you wish to make persistent.

  • There is no problem with source version control systems, because your source files are not altered.

  • Parsing and enhancing bytecode is fast.

  • During debugging, the line numbers reported in your stack traces will correspond exactly to the correct lines in your original source files.

Even with all of these advantages, many developers feel uncomfortable with bytecode enhancement. Thus, the JDO specification does not mandate a particular form of enhancement; each JDO implementation is free to choose the form that it feels best suits its users.

[Note]Note

Kodo JDO uses bytecode enhancement.

Regardless of type, all JDO enhancers are required to be binary-compatible with each other. This means that the final enhanced class can be used not only by the JDO implementation whose enhancer created it, but by any other JDO implementation as well. The binary compatibility requirement ensures that you can package and ship persistent classes to other developers without worrying about what JDO vendor they use. It also means that you can switch JDO vendors without even recompiling your persistent classes.