Table of Contents
Repositories are used to obtain references to (persisted) entities.
The implementation of these repositories depends on the object store in
use; those for the in-memory objectstore won't be suitable for use with
JPA Objects because they naively iterate over all
instances. You'll therefore need to re-implement your repositories. And
for this reason it's best practice to define an interface for your
repositories (or indeed any domain service). You can then switch in
different implementations just by editing
nakedobjects.properties
(see Section 7.1, “Configure Naked Objects”).
It's good practice to put your JPA implementations into a separate Maven module. That way, you can isolate the dependencies on JPA Objects itself just to the code that needs it. The Maven archetype that comes with JPA Objects is designed to work this way; see Appendix A, Using the Maven Archetype for more details.
To understand what goes into the JPA Objects repository implementations, let's start with a little background.
Naked Objects provides generic repository support through its
convenience adapter classes in the Naked Objects applib. Although not
mandatory, it's easiest to have domain objects inherit from
org.nakedobjects.applib.AbstractDomainObject
and
repositories - while prototyping at least - inherit from
org.nakedobjects.applib.AbstractFactoryAndRepository
.
These both inherit from
org.nakedobjects.applib.AbstractContainedObject
,
which in turn provides a Container property to
allow the DomainObjectContainer
to be injected.
The DomainObjectContainer
in effect
is the generic repository.
Also in AbstractContainedObject
are some
convenience methods for searching, each of which just delegates to
similarly named methods in DomainObjectContainer
.
First and most straightforwardly we can request all instances of a given
entity class:
allInstances(Class<T> ofClass):
List<T>
But it is also possible to request all instances matching either a condition. This can be expressed in one of four ways:
allMatches(Class<T> ofClass, String title):
List<T>
With this method we search by title. This makes sense for those classes where the title is relatively small and known to be unique. However, Naked Objects does not itself mandate unique titles; they are just labels that are unique "enough" for the objects being viewed by the end-user. This is also not a good option if the title changes, eg reflecting the state of the object
allMatches(Class<T> ofClass, T pattern):
List<T>
Here we search using a pattern object, sometimes called query-by-example. Only instances whose values match those of the (set) properties of the pattern instance are returned.
allMatches(Class<T> ofClass, Filter<T>
filter): List<T>
The Filter<T>
interface (defined
in the Naked Objects applib) acts as a predicate, so the method
returns only those instances that meet the filter.
allMatches(Class<T> ofClass, Query<T>
query): List<T>
This method is similar to the one for filtering, returning
those instances that meet the query specification. (Again,
Query<T>
is defined in the Naked
Objects applib).
There are similar methods to find the first instance:
firstMatch(Class<T> ofClass, String title):
T
firstMatch(Class<T> ofClass, T pattern):
T
firstMatch(Class<T> ofClass, Filter<T>
filter): T
firstMatch(Class<T> ofClass, Query<T>
query): T
There are also methods to find the first and only (unique) instance:
uniqueMatch(Class<T> ofClass, String title):
T
uniqueMatch(Class<T> ofClass, T pattern):
T
uniqueMatch(Class<T> ofClass, Filter<T>
filter): T
uniqueMatch(Class<T> ofClass, Query<T>
query): T
The difference between Filter<T>
and
Query<T>
in these methods comes down to
where the predicate is evaluated. With
Filter<T>
, the evaluation is in Java. What
that means is that all instances are returned from the object store. In
contrast Query<T>
the evaluation is
performed by the object store implementation. For JPA
Objects, it ultimately corresponds to the "WHERE" clause in a
SQL SELECT statement.
For prototyping you'll find that the first three of these are
supported by both the in-memory object store and also by the XML object
store. Indeed, every object store is likely to support these, because
all they simply require that the object store can return all instances
of a class. However, the version accepting
Query<T>
is different; because the
Query<T>
is evaluated in the object store,
its implementation will in general be specific to the object
store.
That said, there is in fact a default implementation of
Query<T>
, namely
QueryDefault<T>
(in the Naked Objects
applib, again). This implementation simply holds onto a query name and a
set of parameter/argument pairs.
The in-memory object store and XML object store do not support
Query<T>
in any way. JPA
Objects does support Query<T>
,
through QueryDefault<T>
. And this is what
we use in our repository implementations.