Home > Articles > Programming > Java

This chapter is from the book

This chapter is from the book

3.9 JDO Object Model

So far, the examples have used a simple Java class to demonstrate basic concepts. JDO can, of course, be used with much more sophisticated classes than this. In addition to supporting fields of primitive Java types and system classes like String, JDO can handle object references, Java collections, and inheritance of both classes and interfaces.

This section outlines what can and can't be used when developing a persistence-capable class, including the following:

  • The basic field types that can be used within a persistence-capable class.

  • Using references to persistence-capable classes, non-persistence-capable classes, and interfaces.

  • Using standard Java collections.

  • Using arrays.

  • Support for inheritance.

  • The class and field modifiers that can be used.

  • What JDO doesn't support.

3.9.1 Basic types

A persistence-capable class can have fields whose types can be any primitive Java type, primitive wrapper type, or other supported system immutable and mutable classes. Table 3-1 provides a summary of these basic types.

If a persistence-capable class has fields of any of the above types, then by default these fields are persisted in the datastore (providing they are not declared as transient). If a field is a reference to a persistence-capable class, then by default these fields are persisted also. Fields of any other types are not persisted in the data-store by default and need explicit metadata to indicate that they should be persisted. The types of these fields might be a reference to the Java interface, a java.lang.Object, a non-supported system class/interface, or a non-persistence-capable class.

Table 3-1. Supported Basic Types

Primitive Types

Wrapper Classes

Supported System Interfaces

Supported System Classes

boolean

java.lang.Boolean¥

java.util.Collection§

java.lang.String[¥]

byte

java.lang.Byte[¥]

java.util.List*[§]

java.math.BigDecimal[¥]

char

java.lang.Character[¥]

java.util.Map[*][§]

java.math.BigInteger[¥]

double

java.lang.Double[¥]

java.util.Set[§]

java.util.Date

int

java.lang.Integer[¥]

javax.jdo.PersistenceCapable

java.util.Locale[¥]

float

java.lang.Float[¥]

 

java.util.ArrayList[*][§]

long

java.lang.Long[¥]

 

java.util.HashMap[*][§]

short

java.lang.Short[¥]

 

java.util.HashSet[§]

     

java.util.Hashtable[*][§]

     

java.util.LinkedList[*][§]

     

java.util.TreeMap[*][§]

     

java.util.TreeSet[*][§]

     

java.util.Vector[*][§]

JDO defines both mandatory and optional features. A JDO implementation is said to be compliant if it supports all the mandatory features defined by the JDO specification. An implementation may support one or more optional features, in which case it must adhere to what is defined for the optional feature by the JDO specification if it is to be JDO compliant.

From a portability standpoint, an application should not rely on support of an optional feature. But should a particular feature be required, then at least the application is still portable across implementations that support the feature or set of features used. See Chapter 5 for more details on specific optional features.

3.9.2 References

A persistence-capable class can have fields that reference instances of other persistence-capable classes. The following code snippet shows a Book class that has an "author" field, which is a reference to an instance of Author:

public class Book {

  private String name;
  private Author author;
   
   public Book(String name, Author author) {
   
   this.name = name;
   this.author = author;
   }
   
   protected Book() {}
   
   public String getName() {
   
   return name;
   }
   
   public void setName(String name) {
   
   this.name = name;
   }
   
   public Author getAuthor() {
   
   return author;
   }
   
   public void setAuthor(Author author) {
   
   this.author = author;
   }
   }
   

The JDO metadata for this class in Book.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="Book"/>
  </package>
</jdo>

The following code snippet taken from CreateWithReachabilityExample.java shows persistence by reachability at work. Both an Author and a Book instance are created. The Book instance is added to the Author instance, and the Author instance is explicitly made persistent, so the Book instance is automatically made persistent because it is reachable from the Author instance:

tx.begin();

Author author = new Author("Keiron McCammon");

Book book =
  new Book("Core Java Data Objects", "0-13-140731-7");

author.addBook(book);

pm.makePersistent(author);
   
   tx.commit();
   

As well as supporting references to persistence-capable classes, JDO also supports references to Java interfaces and even java.lang.Object. Because fields of these types are not persistent by default, additional metadata is required to denote that the field should be persistent. Any referenced instances should still be instances of a persistence-capable class. (Support for references to non-persistence-capable classes is a JDO optional feature.)

The following code snippet shows a revised Book class that has an "author" field, which now is of type java.lang.Object instead of Author:

public class Book {

  private String name;
  private Object author; // Uses Object rather than Author
   
   /* Rest of code not shown */
   }
   

The major difference here compared to the previous example is the metadata in Book.jdo:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jdo SYSTEM "jdo.dtd">
<jdo>
  <package name="com.corejdo.examples.model">
    <class name="Book">
       <field
   name="author"
   persistence-modifier="persistent"/>
   </class>
   </package>
   </jdo>
   

Because the field's type is java.lang.Object, it is not persistent by default. It must be explicitly denoted as persistent in the metadata for the class. The same would be true if it were a reference to an interface.

A JDO implementation may optionally support references to instances that do not belong to a persistence-capable class. If not supported, a Java class cast exception would be thrown at the time of assignment. (An application intended to run against multiple JDO implementations should not rely on support for persisting non-persistence-capable classes.)

If references to non-persistence-capable classes are supported, then these instances exist in the datastore only as part of the referencing persistent object. It is the responsibility of the application to inform the JDO implementation when an instance of a non-persistence-capable class is modified because the JDO implementation is unable to automatically detect when a field of a non-persistence-capable class is changed.

The JDO implementation can't detect when an instance of a non-persistence-capable class is modified because the class doesn't adhere to the persistence-capable programming style. A persistence-capable class automatically informs the JDO implementation before a field is changed (this is what the byte code enhancement process takes care of), but a non-persistence-capable class does not.

If the JDO implementation is not explicitly notified of changes to non-persistence-capable classes, then the modifications do not get written to the datastore on commit. The easiest way to notify a JDO implementation that a non-persistence-capable instance has been modified is to use the makeDirty() method on JDOHelper:

static void makeDirty(Object pc, String field)

The first argument is the persistent object that references the non-persistence-capable instance. The second argument is the field name of the reference.

JDOHelper

JDOHelper was previously introduced as a way to bootstrap a JDO application and get an instance of a PersistenceManagerFactory. As well as this, JDOHelper has a number of additional methods that act as shortcuts to the various JDO APIs.

The following code snippet shows a non-persistence-capable class called Address that can be used to store the address of an Author:

import java.io.Serializable;

public class Address implements Serializable {

  private String street;
  private String zip;
  private String state;

  public Address(String street, String zip, String state) {

    this.street = street;
    this.zip    = zip;
    this.state  = state;
  }

  /* Additional getters and setters not shown */

  public void setZip ( String zip ) {

    this.zip = zip;
  }
}

Exactly how a JDO implementation manages the fields of non-persistence-capable classes is undefined by JDO. Some implementations may require that a class implement Serializable or follow the JavaBean pattern, or may require that its fields be declared public.

The following code snippet shows a revised Author class that contains a reference to an Address and shows how to set the zip code of the address. The method first calls makeDirty() to inform the JDO implementation that the address is being be modified:

import javax.jdo.*;

public class Author {

  private String  name;
  private Address address;
   
   public Author(String name, Address address) {
   
   this.name    = name;
   this.address = address;
   }
   
   protected Author () {}
   
   public void setZip(String zip) {
   
   JDOHelper.makeDirty(this, "address");
   
   address.setZip(zip);
   }
   }
   

JDOHelper.makeDirty()

It is a best practice to call makeDirty() before making any modifications to a non-persistence-capable instance. Depending on the underlying datastore, the call to makeDirty() may result in a concurrency conflict indicating that changes aren't allowed at that time.

The revised JDO metadata for this 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">
      <field
   name="address"
   persistence-modifier="persistent"/>
   </class>
   </package>
   </jdo>
   

Because the address field is a reference to a non-persistence-capable class, it is necessary to specifically specify that the field should be persistent.

When using non-persistence-capable instances, it is best to modify them only through methods on the referencing persistent object. This way, the persistent object can call makeDirty() on itself before making any changes. If a non-persistence-capable object is passed by reference and modified elsewhere, it becomes hard for the application to ensure that the referencing persistent object is notified of the changes, in which case any changes are ignored.

3.9.3 Collection classes

A persistence-capable class can have fields that reference the standard Java collection classes. Instances of these collection classes exist in the datastore only as part of the referencing persistent object. At a minimum, JDO mandates support for java.util.HashSet; support for ArrayList, HashMap, Hashtable, LinkedList, TreeMap, TreeSet, and Vector is optional. However, most JDO implementations support all these collection classes.

Optional Features

To determine whether an implementation supports the optional collection classes, use the supportedOptions() method on PersistenceManagerFactory. See Chapter 5 for more details.

The following code snippet shows a revised Author class that uses a java.util.HashSet to hold the books that an author has written:

import java.util.*;

public class Author {

  private String name;
  private Set books = new HashSet();
   
   public Author (String name) {
   
   this.name = name;
   }
   
   protected Author () {}
   
   public String getName() {
   
   return name;
   }
   
   public void setName(String name) {
   
   this.name = name;
   }
   
   public void addBook(Book book) {
   
   books.add(book);
   }
   
   public Iterator getBooks() {
   
   return books.iterator();
   }
   }
   

The revised JDO metadata for this class in AuthorWithBooks.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">
      <field name="books">
   <collection
   element-type=
   "com.corejdo.examples.model.Book"/>
   </field>
   </class>
   </package>
   </jdo>
   

Because this class uses a Java collection, additional metadata can be used to declare the class of the instances that are stored in the collection. Because Java collections are un-typed, it is impossible for a JDO implementation to determine this information from the Java class itself.

Additional Metadata

The additional metadata shown for the "books" field is optional; it does not need to be specified. If not specified, the JDO runtime assumes that the collection may contain a reference to any persistent object, as does normal Java.

Even though it is optional, it is best practice to define the element type of a collection because it potentially allows the JDO runtime to optimize how it handles the field both in-memory as well as in the datastore.

Unlike user-defined, non-persistence-capable classes, JDO mandates that the supported collections automatically detect changes and notify the referencing persistent object. A JDO implementation does this by replacing instances of system-defined collection classes with instances of its own equivalent classes that perform this detection. For a new persistent object, this replacement happens during the call to makePersistent(); for existing persistent objects, this occurs when they are retrieved from the datastore. All this is completely transparent to the application. It just means that an application should not reply on a collection being a particular concrete Java class (java.util.HashMap, for example).

3.9.4 Arrays

Support for a persistence-capable class with fields that use Java arrays is optional in JDO. If supported, arrays are similar in nature to user-defined, non-persistence-capable classes except that a JDO runtime may automatically detect changes and notify the referencing persistent object of the modification. For portability, an application should assume responsibility for notifying the referencing persistent object when an array is modified.

With non-persistence-capable classes, it is a best practice to modify arrays only through methods on the referencing persistent object. This way, the referencing persistent object can call makeDirty() on itself before making any change. If an array is passed by reference and modified elsewhere, it becomes hard for the application to ensure that the owning persistent object is notified of the changes, in which case any changes are ignored.

The following code snippet shows a revised Author class that uses an array to store the books that an author has written. As a simplification, the array holds only a single book; in real life, any sized array could have been used:

import java.util.*;

public class Author {

  private String name;
  private Book   books[] = new Book[1];
   
   public Author(String name) {
   
   this.name = name;
   }
   
   protected Author()
   
   public String getName() {
   
   return name;
   }
   
   public void setName(String name) {
   
   this.name = name;
   }
   
   public void addBook(Book book, int i) {
   
   JDOHelper.makeDirty(this, "books");
   
   books[i] = book;
   }
   
   public Book getBook(int i) {
   
   return books[i];
   }
   }
   

The revised JDO metadata for this 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"/>
  </package>
</jdo>

Because the field is an array of a persistence-capable class, no additional metadata is required and the array field is persistent by default.

3.9.5 Inheritance

JDO supports inheritance of both interfaces and classes. Because Java interfaces don't define any fields, a JDO implementation needs to do nothing, so Java interfaces can be used with no real consideration as far as JDO is concerned.

When using class inheritance (abstract or otherwise), JDO needs to be aware of the implementation hierarchy, because each class can define its own fields. In the usual case, where all classes in the inheritance hierarchy are themselves persistence-capable, it is straightforward. The only requirement is to denote the persistence-capable superclass of a class in the JDO metadata.

The following code snippet shows a class that extends the Book class:

public class RevisedBook extends Book {
   
   private Book original;
   
   public RevisedBook(String name, Book original) {
   
   super(name);
   
   this.original = original;
   }
   
   protected RevisedBook() {}
   
   public Book getOriginal() {
   
   return original;
   }
   
   public void setOriginal(Book original) {
   
   this.original = original;
   }
   }
   

The JDO metadata for this class in RevisedBook.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="RevisedBook"
             persistence-capable-superclass="Book"/>
   </package>
   </jdo>
   

The additional metadata denotes the persistence-capable superclass of the class. The persistence-capable-superclass name uses the Java naming rules: If no package is included in the name, the package name is assumed to be the same package as the persistence-capable class.

It is possible for a persistence-capable class to extend a non-persistence-capable class. In this case, any fields defined by the non-persistence-capable class are ignored by JDO and are not persisted in the datastore. It is also possible to have a persistence-capable class extend a non-persistence-capable class, which itself extends a persistence-capable class. In all cases, any fields of a non-persistence-capable class are ignored by JDO; it is the responsibility of the application to manage these fields.

It is best to make all classes in an inheritance hierarchy persistence-capable. This avoids added complications. If this isn't possible and non-persistence-capable classes have to be used, then a persistence-capable subclass should implement the InstanceCallbacks Interface and use the jdoPostLoad(), jdoPreStore(), and jdoPreClear() methods to manage the fields of the non-persistence-capable classes explicitly.

3.9.6 Modifiers

JDO supports all Java class and field modifiers—private, public, protected, static, transient, abstract, final, synchronized, and volatile—with the following caveats:

  • A field declared as transient is not persisted it in the datastore by default. This default behavior can be overridden by explicitly declaring the field as persistent in the class's metadata.

  • A field declared as final cannot be persisted in the datastore; its value can be set only during construction.

  • A field declared as static cannot be persisted in the datastore; it has meaning only at the class level within the JVM.

Apart from static and transient, use of field modifiers is essentially orthogonal to the use of JDO.

3.9.7 What isn't supported

JDO supports most of what can be defined in Java. The major exception is that JDO can't make Java system classes persistence-capable; rather, it mandates support for specific system classes (as already outlined) as fields of a persistence-capable class. Also, classes that depend on an inaccessible or remote state, such as those that use JNI or those that extend system-defined classes, cannot be made persistence-capable and cannot be used as fields of persistence-capable classes.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020