Very few domain objects are standalone; most have properties and/or collections that reference other objects. This creates a problem for persistence technologies: if we load (or resolve) one object from the object store, how do we prevent having to load everything it refers to (and transitively, everything they refer to, and so on).
Lazy loading provides the solution to this, by returning proxies for the referenced objects. Only when these proxies are queried do they perform a further database query. In this way we "walk the graph" piecemeal.
Different JPA providers do this in different ways, and the proxy also varies depending on whether there is lazy loading of a property (referencing a single instance of some other object) or a collection (referencing many instances). JPA Objects uses Hibernate, which works as follows:
for properties, Hibernate returns a proxy to the referenced object, implemented in either CgLib or Javassist. These bytecode libraries are able to create proxies even for (non-final) domain classes.
for collections, Hibernate replaces the original collection
implementation (eg java.util.ArrayList
) with
its own implementation (eg
org.hibernate.PersistentList
).. When this proxy
collection is queried, it too queries the database. The instances
returned can either be resolved objects, or could themselves be
proxies.
The programmer can influence lazy loading by specifying the
fetch
attribute of
@javax.persistence.OneToOne
and
@javax.persistence.ManyToOne
annotations:
The EAGER
strategy is a requirement on the
persistence provider runtime that data must be eagerly
fetched.
The LAZY
strategy is a hint to the
persistence provider runtime that data should be fetched lazily when
it is first accessed.
The only other programming model restriction is that collections
must provide a setter (even if only with private
visibility) so that Hibernate can inject its own collection
implementations.
Naked Objects itself also provides support for lazy loading, and is configured to support it out-of-the-box. This is needed in two main situations:
for the client in client/server deployments; if a user clicks on a collection (in the DnD viewer) then Naked Objects will resolve the collection
for either the server in client/server deployments or for webapp deployments where the object store implementation does not itself support lazy loading
Naked Objects implementation also uses either CgLib or Javassist,
though the implementation differs from Hibernate. In Section 2.5, “Specify a discriminator” we discussed the idea of an
Oid
- a unique identifier for every domain
object. However, this Oid
doesn't just float
around, it is actually associated with a
NakedObject
. This is a wrapper (or adapter) for
the underlying domain object. The Naked Objects framework maintains
mappings so anyone can be looked up from the others:
Naked Objects' lazy loading support is managed through these
NakedObject
adapters. Each adapter keeps track of
the "resolve state" of its corresponding pojo. An unresolved object has
not yet been loaded, so any request to view its contents forces a load
(across the network, for a client, or from the objectstore, for a
server). A CgLib proxy is used to trigger the request to resolve the
domain object if required; ultimately this is marshalled through the
DomainObjectContainer#resolve()
method.
How does all this tie into JPA Objects, though? Well, because Hibernate is used under the covers , we actually switch off Naked Objects' own lazy loading for deployments running server-side or as a webapp. Details of how to do is shown in Section 7.1, “Configure Naked Objects”.