diff --git a/src/docbkx/index.xml b/src/docbkx/index.xml
index 20f51f0a6..5de79734a 100644
--- a/src/docbkx/index.xml
+++ b/src/docbkx/index.xml
@@ -15,6 +15,10 @@
Thomas
Risberg
+
+ Oliver
+ Gierke
+
@@ -38,6 +42,7 @@
This part of the reference documentation details the ...
+
diff --git a/src/docbkx/repositories.xml b/src/docbkx/repositories.xml
new file mode 100644
index 000000000..7a156018f
--- /dev/null
+++ b/src/docbkx/repositories.xml
@@ -0,0 +1,673 @@
+
+
+
+ Repositories
+
+
+ Introduction
+
+ Implementing a data access layer of an application has been
+ cumbersome for quite a while. Too much boilerplate code had to be written.
+ Domain classes were anemic and haven't been designed in a real object
+ oriented or domain driven manner.
+
+ Using both of these technologies makes developers life a lot easier
+ regarding rich domain model's persistence. Nevertheless the amount of
+ boilerplate code to implement repositories especially is still quite high.
+ So the goal of the repository abstraction of Spring Data is to reduce the
+ effort to implement data access layers for various persistence stores
+ significantly
+
+ The following chapters will introduce the core concepts and
+ interfaces of Spring Data repositories.
+
+
+
+ Core concepts
+
+ The central interface in Spring Data repository abstraction is
+ Repository (probably not that much of a
+ surprise). It is typeable to the domain class to manage as well as the id
+ type of the domain class and provides some sophisticated functionality
+ around CRUD for the entity managed.
+
+
+ Repository interface
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ public interface Repository<T, ID extends Serializable> {
+
+ T save(T entity);
+
+ T findById(ID primaryKey);
+
+ List<T> findAll();
+
+ Page<T> findAll(Pageable pageable);
+
+ Long count();
+
+ void delete(T entity);
+
+ boolean exists(ID primaryKey);
+
+ // … more functionality omitted.
+}
+
+
+
+ Saves the given entity.
+
+
+
+ Returns the entity identified by the given id.
+
+
+
+ Returns all entities.
+
+
+
+ Returns a page of entities.
+
+
+
+ Returns the number of entities.
+
+
+
+ Deletes the given entity.
+
+
+
+ Returns whether an entity with the given id exists.
+
+
+
+
+
+ Usually we will have persistence technology specific sub-interfaces
+ to include additional technology specific methods. We will now ship
+ implementations for a variety of Spring Data modules that implement that
+ interface.
+
+
+
+ Query methods
+
+ Next to standard CRUD functionality repositories are usually query
+ the underlying datastore. With Spring Data declaring those queries becomes
+ a four-step process (we use the JPA based module as example but that works
+ the same way for other stores):
+
+
+
+ Declare an interface extending the technology specific
+ Repository sub-interface and type it to the domain class it shall
+ handle.
+
+ public interface PersonRepository extends JpaRepository<User, Long> { … }
+
+
+
+ Declare query methods on the interface.
+
+ List<Person> findByLastname(String lastname);
+
+
+
+ Setup Spring to create proxy instances for those
+ interfaces.
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://www.springframework.org/schema/data/jpa
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/data/jpa
+ http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
+
+ <repositories base-package="com.acme.repositories" />
+
+</beans>
+
+
+
+ Get the repository instance injected and use it.
+
+ public class SomeClient {
+
+ @Autowired private PersonRepoyitory repository;
+
+ public void doSomething() {
+ List<Person> persons = repository.findByLastname("Matthews");
+ }
+
+
+
+ At this stage we barely scratched the surface of what's possible
+ with the repositories but the general approach should be clear. Let's go
+ through each of these steps and and figure out details and various options
+ that you have at each stage.
+
+
+ Defining repository interfaces
+
+ As a very first step you define a domain class specific repository
+ interface to start with. It's got to be typed to the domain class and an
+ ID type so that you get CRUD methods of the
+ Repository interface tailored to
+ it.
+
+
+
+ Defining query methods
+
+
+ Query lookup strategies
+
+ The next thing we have to discuss is the definition of query
+ methods. There's roughly two main ways how the repository proxy is
+ generally able to come up with the store specific query from the
+ method name. The first option is to derive the quer from the method
+ name directly, the second is using some kind of additionally created
+ query. What detailed options are available pretty much depends on the
+ actual store. However there's got to be some algorithm the decision
+ which actual query to is made.
+
+ There's three strategies for the repository infrastructure to
+ resolve the query. The strategy to be used can be configured at the
+ namespace through the query-lookup-strategy attribute.
+ However might be the case that some of the strategies are not
+ supported for the specific datastore. Here are your options:
+
+
+ CREATE
+
+ This strategy will try to construct a store specific query
+ from the query method's name. The general approach is to remove a
+ given set of well-known prefixes from the method name and parse the
+ rest of the method. Read more about query construction in .
+
+
+
+ USE_DECLARED_QUERY
+
+ This strategy tries to find a declared query which will be
+ used for execution first. The query could be defined by an
+ annotation somwhere or declared by other means. Please consult the
+ documentation of the specific store to find out what options are
+ available for that store. If the repository infrastructure does not
+ find a declared query for the method at bootstrap time it will
+ fail.
+
+
+
+ CREATE_IF_NOT_FOUND (default)
+
+ This strategy is actually a combination of the both mentioned
+ above. It will try to lookup a declared query first but create a
+ custom method name based query if no declared query was found. This
+ is default lookup strategy and thus will be used if you don't
+ configure anything explicitly. It allows quick query definition by
+ method names but also custom tuning of these queries by introducing
+ declared queries for those who need explicit tuning.
+
+
+
+
+ Query creation
+
+ The query builder mechanism built into Spring Data repository
+ infrastructue is useful to build constraining queries over entities of
+ the repository. We will strip the prefixes findBy,
+ find, readBy, read,
+ getBy as well as get from the method and
+ start parsing the rest of it. At a very basic level you can define
+ conditions on entity properties and concatenate them with
+ AND and OR.
+
+
+ Query creation from method names
+
+ public interface PersonRepository extends JpaRepository<User, Long> {
+
+ List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
+}
+
+
+ The actual result of parsing that method will of course depend
+ on the persistence store we create the query for. However there are
+ some general things to notice. The expression are usually property
+ traversals combined with operators that can be concatenated. As you
+ can see in the example you can combine property expressions with And
+ and Or. Beyond that you will get support for various operators like
+ Between, LessThan, GreaterThan, Like for the property expressions. As
+ the operators supported can vary from datastore to datastore please
+ consult the according part of the reference documentation.
+
+
+ Property expressions
+
+ Property expressions can just refer to a direct property of
+ the managed entity (as you just saw in the example above. On query
+ creation time we already make sure that the parsed property is at a
+ property of the managed domain class. However you can also traverse
+ nested properties to define constraints on. Assume
+ Persons have Addresses
+ with ZipCodes. In that case a method name
+ of
+
+ List<Person> findByAddressZipCode(ZipCode zipCode);
+
+ will create the property traversal
+ x.address.zipCode. The resolution algorithm starts with
+ interpreting the entire part (AddressZipCode) as
+ property and checks the domain class for a property with that name
+ (uncapitalized). If it succeeds it just uses that. If not it starts
+ splitting up the source at the camel case parts from the right side
+ into a head and a tail and tries to find the according property,
+ e.g. AddressZip and Code. If
+ we find a property with that head we take the tail and continue
+ building the tree down from there. As in our case the first split
+ does not match we move the split point to the left
+ (Address, ZipCode).
+
+ Now although this should work for most cases, there might be
+ cases where the algorithm could select the wrong property. Suppose
+ our Person class has a
+ addressZip property as well. Then our algorithm would
+ match in the first split round already and essentially choose the
+ wrong property and finally fail (as the type of
+ addressZip probably has no code property). To
+ resolve this ambiguity you can use _ inside your
+ method name to manually define traversal points. So our method name
+ would end up like so:
+
+ List<Person> findByAddress_ZipCode(ZipCode zipCode);
+
+
+
+
+
+ Special parameter handling
+
+ To hand parameters to your query you simply define method
+ parameters as already seen in in examples above. Besides that we will
+ recognizes certain specific types to apply pagination and sorting to
+ your queries dynamically.
+
+
+ Using Pageable and Sort in query methods
+
+ Page<User> findByLastname(String lastname, Pageable pageable);
+
+List<User> findByLastname(String lastname, Sort sort);
+
+List<User> findByLastname(String lastname, Pageable pageable);
+
+
+ The first method allows you to pass a Pageable
+ instance to the query method to dynamically add paging to your
+ statically defined query. Sorting options are handed via
+ the Pageable instance, too. If you only
+ need sorting, simply add a Sort parameter to your method.
+ As you also can see, simply returning a
+ List is possible as well. We will then
+ not retrieve the additional metadata required to build the actual
+ Page instance but rather simply
+ restrict the query to lookup only the given range of entities.
+
+
+ To find out how many pages you get for a query entirely we
+ have to trigger an additional count query. This will be derived from
+ the query you actually trigger by default.
+
+
+
+
+
+ Creating repository instances
+
+ So now the question is how to create instances and bean
+ definitions for the repository interfaces defined.
+
+
+ Spring
+
+ The easiest way to do so is by using the Spring namespace that
+ is shipped with each Spring Data module that supports the repository
+ mechanism. Each of those includes a repositories element that allows
+ you to simply define a base packge Spring shall scan for you.
+
+ <?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://www.springframework.org/schema/data/jpa
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/data/jpa
+ http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
+
+ <repositories base-package="com.acme.repositories" />
+
+</beans:beans>
+
+ In this case we instruct Spring to scan
+ com.acme.repositories and all it's sub packages for
+ interfaces extending the appropriate
+ Repository sub-interface (in this case
+ JpaRepository). For each interface
+ found it will register the presistence technology specific
+ FactoryBean to create the according
+ proxies that handle invocations of the query methods. Each of these
+ beans will be registered under a bean name that is derived from the
+ interface name, so an interface of
+ UserRepository would be registered
+ under userRepository. The base-package
+ attribute allows to use wildcards, so that you can have a pattern of
+ packages parsed.
+
+
+ Using filters
+
+ By default we will pick up every interface extending the
+ persistence technology specific
+ Repository sub-interface located
+ underneath the configured base package and create a bean instance
+ for it. However, you might want to gain finer grained control over
+ which interfaces bean instances get created for. To do this we
+ support the use of <include-filter /> and
+ <exclude-filter /> elements inside
+ <repositories />. The semantics are exactly
+ equivalent to the elements in Spring's context namespace. For
+ details see Spring reference documentation on these
+ elements.
+
+ E.g. to exclude certain interfaces from instantiation as
+ repository, you could use the following configuration:
+
+
+ Using exclude-filter element
+
+ <repositories base-package="com.acme.repositories">
+ <context:exclude-filter type="regex" expression=".*SomeRepository" />
+</repositories>
+
+
+ This would exclude all interface ending on
+ SomeRepository from being
+ instantiated.
+
+
+
+
+ Manual configuration
+
+ If you'd rather like to manually define which repository
+ instances to create you can do this with nested <repository
+ /> elements.
+
+ <repositories base-package="com.acme.repositories">
+ <repository id="userRepository" />
+</repositories>
+
+
+
+
+
+ Standalone usage
+
+ You can also use the repository infrastructure outside of a
+ Spring container usage. You will still need to have some of the Spring
+ libraries on your classpath but you can generally setup repositories
+ programatically as well. The Spring Data modules providing repository
+ support ship a persistence technology specific RepositoryFactory that
+ can be used as follows:
+
+
+ Standalone usage of repository factory
+
+ RepositoryFactorySupport factory = … // Instantiate factory here
+UserRepository repository = factory.getRepository(UserRepository.class
+
+
+
+
+
+
+ Custom implementations
+
+
+ Adding behaviour to single repositories
+
+ Often it is necessary to provide a custom implementation for a few
+ repository methods. Spring Data repositories easily allow provide custom
+ repository code and integrate it with generic CRUD abstraction and query
+ method functionality. To enrich a repository with custom functionality
+ you have to define an interface and an implementation for that
+ functionality first and let the repository interface you provided so far
+ extend that custom interface.
+
+
+ Interface for custom repository functionality
+
+ interface UserRepositoryCustom {
+
+ public void someCustomMethod(User user);
+}
+
+
+
+ Implementation of custom repository functionality
+
+ class UserRepositoryImpl implements UserRepositoryCustom {
+
+ public void someCustomMethod(User user) {
+ // Your custom implementation
+ }
+}Note that the implementation itself does not depend on
+ Spring Data and can be a regular Spring bean. So you can either use
+ standard dependency injection behaviour to inject references to other
+ beans, take part in aspects and so on.
+
+
+
+ Changes to the your basic repository interface
+
+ public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
+
+ // Declare query methods here
+}Let your standard repository interface extend the custom
+ one. This makes CRUD and custom functionality available to
+ clients.
+
+
+
+ Configuration
+
+ If you use namespace configuration the repository infrastructure
+ tries to autodetect custom implementations by looking up classes in
+ the package we found a repository using the naming conventions
+ appending the namespace element's attribute
+ repository-impl-postfix to the classname. This suffix
+ defaults to Impl.
+
+
+ Configuration example
+
+ <repositories base-package="com.acme.repository">
+ <repository id="userRepository" />
+</repositories>
+
+<repositories base-package="com.acme.repository" repository-impl-postfix="FooBar">
+ <repository id="userRepository" />
+</repositories>
+
+
+ The first configuration example will try to lookup a class
+ com.acme.repository.UserRepositoryImpl to act
+ as custom repository implementation, where the second example will try
+ to lookup
+ com.acme.repository.UserRepositoryFooBar.
+
+
+
+ Manual wiring
+
+ The approach above works perfectly well if your custom
+ implementation uses annotation based configuration and autowring
+ entirely as will be trated as any other Spring bean. If your customly
+ implemented bean needs some special wiring you simply declare the bean
+ and name it after the conventions just descibed. We will then pick up
+ the custom bean by name rather than creating an own instance.
+
+
+ Manual wiring of custom implementations (I)
+
+ <repositories base-package="com.acme.repository">
+ <repository id="userRepository" />
+</repositories>
+
+<beans:bean id="userRepositoryImpl" class="…">
+ <!-- further configuration -->
+</beans:bean>
+
+ This also works if you use automatic repository lookup without
+ defining single <repository /> elements.
+
+
+ In case you are not in control of the implementation bean name
+ (e.g. if you wrap a generic repository facade around an existing
+ repository implementation) you can explicitly tell the
+ <repository /> element which bean to use as custom
+ implementation by using the repository-impl-ref
+ attribute.
+
+
+ Manual wiring of custom implementations (II)
+
+ <repositories base-package="com.acme.repository">
+ <repository id="userRepository" repository-impl-ref="customRepositoryImplementation" />
+</repositories>
+
+<bean id="customRepositoryImplementation" class="…">
+ <!-- further configuration -->
+</bean>
+
+
+
+
+
+ Adding custom behaviour to all repositories
+
+ In other cases you might want to add a single method to all of
+ your repository interfaces. So the approach just shown is not feasible.
+ The first step to achieve this is adding and intermediate interface to
+ declare the shared behaviour
+
+
+ An interface declaring custom shared behaviour
+
+ public interface MyRepository<T, ID extends Serializable>
+ extends JpaRepository<T, ID> {
+
+ void sharedCustomMethod(ID id);
+}
+
+
+ Now your individual repository interfaces will extend this
+ intermediate interface to include the functionality declared. The second
+ step is to create an implementation of this interface that extends the
+ persistence technology specific repository base class which will act as
+ custom base class for the repository proxies then.
+
+
+ If you're using automatic repository interface detection using
+ the Spring namespace using the interface just as is will cause Spring
+ trying to create an instance of
+ MyRepository. This is of course not
+ desired as it just acts as indermediate between
+ Repository and the actual repository
+ interfaces you want to define for each entity. To exclude an interface
+ extending Repository from being
+ instantiated as repository instance annotate it with
+ @NoRepositoryBean.
+
+
+
+ Custom repository base class
+
+ public class MyRepositoryImpl<T, ID extends Serializable>
+ extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {
+
+ public void sharedCustomMethod(ID id) {
+ // implementation goes here
+ }
+}
+
+
+ The last step to get this implementation used as base class for
+ Spring Data repositores is replacing the standard
+ RepositoryFactoryBean with a custom one using a
+ custom RepositoryFactory that in turn creates
+ instances of your MyRepositoryImpl class.
+
+
+ Custom repository factory bean
+
+ public class MyRepositoryFactoryBean<T extends JpaRepository<?, ?>
+ extends JpaRepositoryFactoryBean<T> {
+
+ protected RepositoryFactorySupport getRepositoryFactory(…) {
+ return new MyRepositoryFactory(…);
+ }
+
+ private static class MyRepositoryFactory extends JpaRepositoryFactory{
+
+ public MyRepositoryImpl getTargetRepository(…) {
+ return new MyRepositoryImpl(…);
+ }
+
+ public Class<? extends RepositorySupport> getRepositoryClass() {
+ return MyRepositoryImpl.class;
+ }
+ }
+}
+
+
+ Finally you can either declare beans of the custom factory
+ directly or use the factory-class attribute of the Spring
+ namespace to tell the repository infrastructure to use your custom
+ factory implementation.
+
+
+ Using the custom factory with the namespace
+
+ <repositories base-package="com.acme.repository"
+ factory-class="com.acme.MyRepositoryFactoryBean" />
+
+
+
+
\ No newline at end of file