The Exceptions of JDO


The JDOException class is the root of all the exceptions defined by JDO. It is derived from RuntimeException. Because RuntimeException and all classes descendent from it are unchecked exceptions, they do not have to be caught in the method or declared in the method's throws clause. Except for RuntimeException and the classes that are derived from it, the Exception type and all exceptions derived from it are checked exceptions. Checked exceptions must either be caught in the method or declared in the method's throws clause. JDO does not define or use any checked exceptions.

As a general rule, JDO throws only JDOException exceptions or the various types of exceptions derived from it. There are a few cases where the JDO specification specifically mentions the possibility of other runtime exceptions. If the application throws runtime exceptions from the callback methods of the Synchronization interface or the InstanceCallbacks interface, it is likely to see these exceptions coming back from JDO as well.

Figure 7-3 shows the UML class diagram of the JDOException class. As Figure 7-3 indicates, JDOException derives from java.lang.RuntimeException.

click to expand
Figure 7-3: The class diagram of the JDOException class

Most Java APIs do not use unchecked exceptions as their primary exception type. JDO uses unchecked exceptions because enhancement adds code that may throw a JDOException. If checked exceptions were thrown by the enhancementadded code, some method signatures in the application data classes would have to be changed. Because of the ramifications for the rest of the application's code, changing method signatures is impractical. By deriving JDOException from RuntimeException, the implications of enhancing an application data class are limited to the class itself and the friendly classes that directly access its managed fields.

JDOException Constructors

The class has seven constructors.

 public JDOException() public JDOException(String msg) public JDOException(String msg, Throwable[] nested) public JDOException(String msg, Throwable nested) public JDOException(String msg, Object failed) public JDOException(String msg, Throwable[] nested, Object failed) public JDOException(String msg, Throwable nested, Object failed) 

These constructors accept several different combinations of four parameters: a message, a failed object, a nested exception, and an array of nested exceptions. The class has a no-arg constructor as well.

All of the derived types of JDOException are marker subclasses of JDOException. They contain the same methods, state, and constructors.

Getting Nested Exceptions

One or more nested exceptions can be stored in a JDOException during construction. The getNestedException method retrieves the nested exceptions.

 public Throwable[] getNestedExceptions() 

This method returns an array of type java.lang.Throwable, which is the base type of all Java exceptions. When there are no nested exceptions, this method returns null.

Getting the Failed Object

When an exception arises because of an action on a particular managed object, JDO associates that application data object with the exception generated. The getFailedObject method returns the associated application data object.

 public Object getFailedObject() 

Not all JDO exceptions have a failed object associated with them. When provided, the application may use the failed object in its recovery from the failure. For example, the application may need to evict the persistent objects that are associated with a JDOOptimisticVerificationException.

Overriden Methods

Because it is derived from RuntimeException, JDOException is three generations removed from its superclass Throwable. JDOException overrides some of the methods of its Throwable superclass. The toString and printStackTrace methods have been modified to include information on the nested exceptions. JDOException does not provide for transporting the stack trace across serialization.

As a general rule, in an n-tier architecture, the layer that is using JDO should catch the JDOExceptions. This layer of code can either handle the error condition or reflect a new exception back to its client.

A General Strategy for Handling JDO Exceptions

Handling a JDO exception is no different from handling any other type of exception with one caveat. Because all JDO exceptions are unchecked during compilation, it is possible to write a good deal of code and have some impressive prototypes and early versions before you realize that you must consider exception handling and its implications on your architecture. The next two sections provide an overview of how to handle exceptions in general and JDO exceptions in particular.

Although JDO does not define or throw any checked exceptions, the application can still do so. Good application designs use checked exceptions. Consequently, the need for JDO to throw unchecked exceptions is not an excuse to avoid checked exceptions in the application's design. In fact, at the point where the application handles the JDO exceptions, it should generally have the option to throw an application-defined checked exception.

General Exception Handling Strategies

Some Java programmers have only one exception handling strategy. They catch and ignore, as in the following bit of code:

 try    {    doSomethingThatMayThrowException();    } catch (Exception ignore)    {    // exception ignored    } 

The catch-and-ignore strategy is occasionally the appropriate exception handling, but more often, it is totally inappropriate. It is usually inappropriate because it does nothing to recover, report, pass on, or repackage the exception.

A reasonable strategy for unchecked exceptions is to simply ignore them. This is not a catch-and-ignore strategy. The simply-ignore strategy does not catch the exception; instead, it relies on the calling code to handle the problem. In the case of Error exception types, which are also unchecked exceptions, almost every program uses this strategy, since there is very little that an application can do that is useful when the JVM throws an Error. It is almost always better to pretend that it will not happen and to stay out of the way when it does. The simply-ignore strategy is also used for checked exceptions when the exception type is declared in the method's throws clause. In essence, the simply-ignore strategy passes the buck to the calling method.

The third strategy, catch-and-handle, is a category for a number of related strategies. The handling part could be any number of actions, including recover, log, wrap, and throw, or construct different exception type and throw. The point of the catch-and-handle strategy is to do something useful with the exception. If you cannot do anything useful with the exception, then you can either catch and ignore the exception, or simply ignore the exception.

A Strategy to Handle JDO Exceptions

There are two types of code situations that can lead to JDO exceptions. In the first situation, the application calls a specific JDO method, such as the commit method in Transaction or the execute method in Query. In this case, catch-and-handle is often the appropriate strategy. In the second situation, the application is using the application data objects, and the calls to JDO are occurring transparently. Some JDO exceptions arise from programming errors. Perhaps the application attempted to read or write a persistent field outside of a transaction. Other JDO exceptions arise from operational circumstances. The datastore service may go down, or a transaction may fail.

In short, the potential for JDO exceptions is everywhere in the code that uses JDO or that uses persistent application data objects. For that reason, a good approach for dealing with JDO exceptions is to wrap the JDO-dependent code into an application data model, or component, that encapsulates the application data classes and the application's use of JDO. Because it encapsulates all the code that gives rise to JDO exceptions, the application data model also encapsulates the exception handling code for JDO exceptions.

Unmanaged objects do not throw JDO exceptions. Although the enhancement-added code is still present in the application data class, unmanaged application data objects do not invoke this code. Consequently, unmanaged data objects can be returned from the application data model without yielding ground on the encapsulation of JDO exceptions.

A data model that is appropriate to the application's architecture can isolate all the code that handles JDO exceptions. The appropriate handling depends on both the application's architecture and the particular type of JDO exception.

Handling JDO Exceptions in Different Application Architectures

Chapters 9 through 11 explore in detail three implementations of the same set of requirements for a reservation system. Chapter 9 examines a Swing implementation for a client/server architecture, Chapter 10 examines a Web application, and Chapter 11 examines an EJB implementation. The JDO exception handling for each of these architectures is described in detail in these chapters, but this is the appropriate place to give an overview of the similarities and differences in handling JDO exceptions in the different architectures.

In the case of Web applications using servlets and JavaServer Pages (JSPs) and in the case of Swing applications that are client/server applications, the application data model is a facade in front of the code that uses JDO and the application data classes. The application data model provides all of the persistent services needed by the application.

Swing applications cannot tolerate uncaught exceptions in the message dispatch loop. They also need to show some reasonable behavior even when the network or database is down. As a result, Swing applications need an application data model that strongly encapsulates the application data classes and the use of JDO. The Swing widgets also need fine-grained access to persistent state. A JTable may present a row for every persistent object and a column for each persistent field. As a result, Swing applications need an application data model that is fine grained. Since the Swing widgets are not equipped to handle the possible exceptions, the application data model must use Swing to report the unfavorable conditions that it may encounter. A Swing application's data model does not throw exceptions, it reports them. In a Swing application, the life cycle of the data model may coincide with the life cycle of the application.

In contrast to a Swing application, a Web application can be built with a strong separation between the model, the view, and the controller, using a design pattern by the same name, Model-View-Controller (MVC). In MVC, the controller uses the model. When the model throws exceptions, the controller handles them. The controller usually does one of two things when it receives an exception from the model: log the exception and request a view (JSP) that shows a generic fault page to the user, or log the exception and request a view that shows a detailed fault page to the user. The choice is often configurable. The data model for a Web application is usually more coarse grained than the data model for a Swing application. Its methods can return a graph of objects that the view can navigate for the information that it needs. Unlike in Swing, the life cycle of the data model in a Web application is usually shorter than the lifetime of the Web application. It may coincide with the lifetime of the HTTP request.

Unlike Swing applications and Web applications, EJB components are not complete applications, but rather the building blocks of the application. EJBs are generally used to build a data model or data service for the application, which might be a Swing application or a Web application. The design of EJBs and their containers provides a framework, or programming model, that emphasizes encapsulation. The main issue for using JDO within an EJB is how to use JDO within the programming model that EJBs provide.

The Various JDO Exceptions

Figure 7-4 shows the class hierarchy of the exception types derived from JDOException. The inheritance tree shows JDOException at the top level with several levels of derived marker classes below it.

click to expand
Figure 7-4: The class hierarchy for JDO exceptions

Although Figure 7-4 shows all the exceptions that JDO defines, the JDO implementation may create additional exception types that derive from any of the JDO-defined types. The implementation may throw an exception of one of its derived types or of any of the JDO-defined types. As a result, when the application receives an exception that is assignment compatible with JDOException, the exception may not be assignment compatible with either JDOCanRetryException or JDOFatalException. The same logic applies throughout the hierarchy.

There are several reasons to understand the purpose for each defined JDO exception type. If you need to define an exception type that derives from one of the classes on the JDOException inheritance tree, you will want to pick the exception type that is closest to your purpose. If you are writing code to handle the exceptions in the JDOException inheritance tree, then you may handle different types of JDO exceptions differently.

JDOException

JDOException is the base type of all exceptions thrown by the JDO implementation. Except in a few situations, if the implementation throws any other type of exception, it either results from a bug in the implementation or from a callback to application-written code. When the JDO implementation throws an exception that is assignment compatible with this type, it is likely that the exception is an instance of a more-derived JDO exception type. Nonetheless, the application should assume that exceptions of this type may be thrown.

JDOCanRetryException and JDOFatalException are the two exception types derived from JDOException. The JDOCanRetryException and its subclasses indicate attempted operations that were not successful, but that might be made successful by varying something under the control of application code. More importantly, the JDOCanRetryException indicates that the transaction, if active, remains active and the persistence manager remains usable.

The JDOFatalException and its subclasses indicate fundamental, pervasive, or irreversible error conditions. For example, if the datastore or distributed transaction manager rolls back a transaction during commit, then that transaction is lost and cannot be restarted or committed. In some cases, the error condition may be pervasive and require that the application either terminate or take action to recover. If a JDOFatalException arises because of an operation on a closed persistence manager, the application must obtain a new persistence manager to continue accessing persistent objects. Otherwise, the application or the component should terminate. Failure to do one or the other may mean an endless series of exceptions.

JDOCanRetryException

JDOCanRetryException is first of the two derived types of JDOException. When the JDO implementation throws an exception that is assignment compatible with this type, it is indicating that the JDO runtime is intact and functioning properly and that the error condition that gave rise to the exception is localized to the particular JDO functionality that was invoked. As a result, as far as JDO is concerned, the application can retry the operation using different information, take some type of corrective action, or continue along using JDO in some other way.

Although JDO may be sanguine about the application's opportunity to recover, in fact, the application may not be able to recover because the error condition was not anticipated. For these situations, the appropriate handling is to abort the task at hand, either by throwing a checked exception or by returning a reasonable return value. At the same time, notification must be given. The application could notify the administrator by an entry in the error log, or notify the user by a visible error report, or notify the caller by throwing a checked exception.

JDO defines two exception types that derived from JDOCanRetryException: JDODataStoreException and JDOUserException.

JDODataStoreException

When the JDO implementation throws an exception that is assignment compatible with JDODataStoreException, it is indicating that the error arose while using the underlying datastore. The specification offers little additional guidance on when to expect exceptions of this type.

JDOObjectNotFoundException

The JDOObjectNotFoundException is derived from JDODataStoreException. Sometimes, JDO expects to find an object's persistent state in the datastore, but due to transactions in other persistence managers (or outside of JDO), the object's state no longer exists in the datastore. JDO might discover the object missing when the application calls the persistence manager's getObjectById method, or JDO might find the object missing when it attempts to transparently load the object's state from the datastore. In these cases, JDO throws a JDOObjectNotFoundException. The transaction, if active, remains active.

By calling the exception's getFailedObject method, the application can obtain the persistent object whose state is missing. By getting the persistent object's identity, the application can determine which object is missing.

If the object's state is discovered missing during transaction commit, then this exception is nested within a JDOFatalDataStoreException.

JDOUserException

JDOUserException arises from a grab bag of exception conditions that are localized to particular JDO operations and do not threaten the usability of the persistence manager or JDO runtime. The possible error conditions are quite numerous and include the following:

  • Attempt to change application identity when the new identity is already in use.

  • Attempt to make persistent an application data object when the object's application identity is already in use.

  • Attempt to reuse an application data object with nondurable identity after it becomes nontransactional.

  • Attempt to access a non-key persistent field or change any persistent field in a persistent-deleted object.

  • Attempt to perform a JDO operation on an application data object when its state does not support that operation, such as an attempt to make persistent and dirty objects either nontransactional or transient, or an attempt to delete transient objects.

  • Attempt to use an identity object that is not recognized by the JDO implementation.

  • Attempt to perform a persistent operation that requires an active transaction when a transaction has not been started.

  • Attempt to perform a persistent operation on an application data object that is being managed by a different persistence manager than the one being used to perform the operation.

  • Attempt to change a JDO property at a time when the property cannot be changed. For example, an attempt to configure the PersistenceManagerFactory when it is no longer configurable, or an attempt to alter the Optimistic property of a transaction after the transaction is started.

  • Passing an object whose class is not enhanced to a JDO operation that requires a PersistenceCapable object.

  • Attempt to get an extent for an application data class when the JDO metadata specifies that the class does not have an extent.

  • Using a query filter that cannot be parsed during a query compile or execute operation.

  • Failure of a modified, persistent field to meet the field restrictions for the null-value attribute of the field tag in the JDO metadata. In other words, a persistent field was not supposed to contain a null value, but it did.

  • Attempt to use an application identity object in the persistence manager's getObjectById method when the identity object contains at least one key field with a null value.

JDOUnsupportedOptionException

JDOUnsupportedOptionException is derived from JDOUserException. It indicates that the JDO implementation does not support the configuration or use of an optional feature defined by the specification. Several scenarios might lead to exceptions of this type:

  • If the implementation does not support a configurable property, then attempts to set the property cause the exception.

  • If the implementation does not support a JDO management state, then operations that would normally cause an application data object to move into the unsupported management state throw the exception.

  • If the implementation does not support an optional operation, then using that operation causes the exception.

For example, any of the following actions throw the JDOUnsupportedOptionException:

  • Attempting to set the NontransactionRead property when the implementation does not support the javax.jdo.option.NontransactionalRead optional feature

  • Calling the persistence manager's makeTransactional method for an unmanaged application data object when the application does not support the javax.jdo.option.TransientTransactional optional feature

  • Attempting to change the application-defined key fields of a persistent object when the implementation does not support the javax.jdo.option.ChangeApplicationIdentity optional feature

The application can verify most of the optional features of an implementation by checking the strings returned from the persistence manager factory's supportedOptions method, as described in Chapter 6.

JDOFatalException

JDOFatalException is the second of the two derived types of JDOException. When the JDO implementation throws an exception of this type, it is indicating a serious error condition. A variety of causes can give rise to a JDOFatalException. The cause may be a defect in the application's logic, a defect in the application's configuration, an unavailable data store, a closed transactional context, or a defect in the JDO implementation.

JDO defines three exception types, JDOFatalDataStoreException, JDOFatalInternalException, and JDOFatalUserException, that are derived from JDOFatalException. As with all of the JDO exceptions, the application should assume that exceptions may be thrown that are assignment compatible with JDOFatalException but not assignment compatible with any of its derived types.

JDOFatalDataStoreException

When the JDO implementation throws an exception that is assignment compatible with JDOFatalDataStoreException, it is indicating a significant problem in its interaction with the datastore. Before throwing this exception, JDO rolls back the transaction if it is active.

If the application throws an exception of this type in a callback method, then it is the application's responsibility to roll back the transaction prior to throwing the exception.

JDOOptimisticVerificationException

JDOOptimisticVerificationException is derived from JDOFatalDataStoreException. JDO throws a JDOOptimisticVerificationException when at least one transactional and persistent object fails the concurrency check during the commit of an optimistic transaction. The JDOOptimisticVerificationException thrown from the commit method contains a nested array of exceptions of the same type, one for each transactional and persistent object that failed the concurrency check.

When JDO throws this exception, the optimistic transaction is rolled back. If transaction's RestoreValues property is true, the application should evict the failed objects. This is not required if the RestoreValues property is false, as eviction is automatic upon rollback. To evict the failed objects, the application iterates the array of nested exceptions obtained from the exception's getNestedExceptions method. For each nested exception, the application should obtained the persistent object from the exception's getFailedObject method and evict it. Failure to evict the persistent state of the failed objects means that the failed objects, which remain persistent, continue to have the outdated state that caused the failure.

JDOFatalInternalException

Exceptions that are assignment compatible with JDOFatalInternalException indicate a defect in the JDO implementation's logic. Exceptions of this type should be reported as a bug to the JDO vendor.

JDOFatalUserException

When the JDO implementation throws an exception that is assignment compatible with a JDOFatalUserException, it is indicating a significant problem in the attempt to satisfy the user's request. Three problems in particular cause JDO to throw exceptions of this type.

  • An attempt was made to get a PersistenceManagerFactory from the getPersistenceManagerFactory method in JDOHelper, and the implementation class specified in the javax.jdo.PersistenceManagerFactoryClass property is not found in the implementation.

  • An enhanced application data class is being used but the JDO metadata for this class cannot be found.

  • An attempt to use a closed PersistenceManager was detected.

Other Runtime Exceptions the JDO Implementation May Throw

The JDO specification mentions several cases where the implementation may throw unchecked exceptions that are not assignment compatible with JDOException.

JDO determines what types of objects can be assigned to persistent fields that are of type Object or of application-defined interface types. When the application makes the assignment, if the object is managed, then JDO checks the type being assigned and throws a ClassCastException if the type is not supported.

Some of the methods of the persistence manager factory require a Collection or array type. These methods include evictAll, refreshAll, and retrieveAll. If the collection object or array object is null, these methods throw a NullPointerException.

Collections that are returned as query results and extents can be iterated. The query results can be closed by calling the close or closeAll methods in the Query interface. Likewise, the extent iterators can be closed by calling the close or closeAll methods in the Extent interface. Iteration after the close operation results in a NoSuchElementException. This exception may also arise from executing a query that uses a collection, rather than an extent, for its candidates. If the collection is altered after it has been used to set the query's candidates, the query execution may throw a NoSuchElementException.

Both extents and the results collections returned from queries are unmodifiable. Attempts to add or remove elements directly or through an iterator yield an UnsupportedOperationException.

Code Examples That Handle JDO Exceptions

The earlier sections explain the principles for implementing an exception handling strategy when using JDO. This section examines three code examples taken from the Swing client/server implementation of the Maine Lighthouse Reservation Service. This example application is found in the JDO Learning Tools, which Chapter 8 introduces. In addition, Chapter 9 discusses the Swing version of the Maine Lighthouse Reservation Service example in detail.

Handling an Optimistic Lock Failure

Optimistic lock failures occur when the transaction's Optimistic property is true and the version of the persistent state of a transactional object is out-of-date with respect to the version stored in the datastore. This happens because another transaction made an update to the same persistent state after JDO loaded the persistent state for the persistent object in memory. The Swing implementation of the Maine Lighthouse Reservation Service uses optimistic transactions because they are appropriate for long-running transactions.

Listing 7-4 shows the commitTransaction method from the ReservationService class, which is found in the com.ysoft.jdo.book.resort.local.service package. This version of ReservationService exposes transactional boundaries to its client. Notice that this method has only two lines of productive code in its try block. It closes any outstanding query results, and it commits the transaction.

Listing 7-4: Handling a Failed Optimistic Transaction

start example
 public void commitTransaction() throws OptimisticReservationException    {    try       {       cleanupQueries();       // Using member field: javax.jdo.Transaction tx;       tx.commit();       }    // catch JDO 1.0.1 optimistic failures    catch (JDOOptimisticVerificationException e)       {       // Eviction not needed, since the combination of rollback and       // RestoreValues == false evicts all persistent-dirty objects       throw new OptimisticReservationException(       "Concurrent changes by other users prevented your changes, try again.");       }    } 
end example

Since the method in Listing 7-4 commits an optimistic transaction, it expects optimistic lock failures from time to time. In the catch block, the method catches the JDOOptimisticVerficationException and throws an application-defined checked exception. Converting to a checked exception creates a more friendly exception message and puts the calling code on notice that this exception may arise. Since this example has the transaction's RestoreValues property set to false in the property file used to obtain a persistence manager, JDO evicts all persistent-dirty and persistent-clean objects when it rolls back the transaction before throwing the JDOOptimisticVerificationException.

Catching All Exceptions When Explicitly Using JDO

In the Swing application, the ReservationClient class initializes and wires the JComponent widgets of the user interface. These widgets use the ReservationClientModel class, which is the application's data model. The data model provides all the data needed by the widgets, and it shields the widgets from all of the dependencies of connecting to transactional and remote data. The ReservationClientModel in turn uses the ReservationService, a portion of which was shown in Listing 7-4. The Swing client contained in the ReservationClient class and the ReservationClientModel class are contained in the com.ysoft.jdo.book.resort.local.client.gui package.

Listing 7-5 shows the submit method of the ReservationClientModel. The submit method calls the commitTransaction method shown in Listing 7-4. As can be seen, the submit method encapsulates all of the exceptions that may be thrown from the explicit use of JDO that occurs within the ReservationService. It has three catch blocks, one for the application-defined checked exception OptimisticReservationException, one for JDOFatalException, and one for all other runtime exceptions.

Listing 7-5: Handling All Exceptions When Explicitly Using JDO

start example
 public void submit()    {    if (isViewReady())       {       try          {          service.commitTransaction();          service.beginTransaction();          setView(VIEW_CUSTOMERS_RESERVATIONS);          fireModelChangeNewData(VIEW_CHANGED);          }       catch (OptimisticReservationException e)          {          // start the transaction before handing exception off to GUI          service.beginTransaction();          MessageHandler.reportException(                ReservationClient.rcReservationClient, e);          // the rollback evicted old data          fireModelChangeNewData(DATA_CHANGED);          }       catch (JDOFatalException e)          {          MessageHandler.reportException(                ReservationClient.rcReservationClient, e);          MessageHandler.reportWarning(                ReservationClient.rcReservationClient, "Disconnecting");          disconnect();          }       catch (RuntimeException e)          {          MessageHandler.reportException(                ReservationClient.rcReservationClient, e);          }       }    } 
end example

The handling in each catch block is different. When an OptimisticReservationException is caught, the code first starts a new transaction and then reports the situation to the user via a pop-up window. It then fires an event informing the application's JTable, which is listening, that the data has changed. When a JDOFatalException is caught, the code informs the user of the circumstances and of the subsequent disconnection from persistent data. In the case of all other runtime exceptions, which include all JDO exceptions other than the explicitly caught JDOFatalException, the code notifies the user and does nothing else.

Listing 7-5 is intended to be illustrative rather than definitive. It illustrates three different catch-and-handle responses in an application data model that cannot throw exceptions to the code that calls it.

Catching All Exceptions When Implicitly Using JDO

A JDO exception may be thrown when the JDO API is explicitly called, but an exception can also arise from the transparent, implicit use of JDO in the application data class. To the widgets in the Swing app, it makes no difference. Any uncaught exceptions that arrive at the widget will cause problems in the Swing framework. As a result, the application data model for a Swing application must catch and handle all of the runtime exceptions that arise from using JDO implicitly.

Listing 7-6 contains the getReservationDate method of the ReservationClientModel class. This method is called by the JTable when it needs the reservation date for a row at an indexed position. The exception handling code for this method is very similar to the exception handling code for the submit method shown in Listing 7-5.

Listing 7-6: Handling All Exceptions When Implicitly Using JDO

start example
 Date getReservationDate(int index)    {    Date retv = null;    try       {       if (index >= 0 && index < numWeeks)          {          Week w = (Week) listOfWeeks.get(index);          retv = w.getStartOfWeek();          }       }    catch (JDOFatalException e)       {       MessageHandler.reportException(ReservationClient.rcReservationClient, e);       MessageHandler.reportWarning(             ReservationClient.rcReservationClient, "Disconnecting");       rcm.disconnect();       }    catch (RuntimeException e)       {       MessageHandler.reportException(ReservationClient.rcReservationClient, e);       }    return retv;    } 
end example

Unlike the submit method, the try block in the getReservationDate method does not call JDO explicitly, nor does it call any methods that call JDO explicitly. Instead, JDO is called implicitly when the getStartOfWeek method is called. Because the weeks are persistent application data objects, enhancement-added code is called in the getStartOfWeek method. If you look in the Week class, you will find a simple accessor method that has one line of working code:

      return start; 

The implicit calls to JDO that support transparent persistence are added during the enhancement step. For that reason, they are not visible in the source.




Using and Understanding Java Data Objects
Using and Understanding Java Data Objects
ISBN: 1590590430
EAN: 2147483647
Year: 2005
Pages: 156
Authors: David Ezzio

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net