From 8e3b0cb1e6eea4243d65ad410aed25bd497f0d76 Mon Sep 17 00:00:00 2001 From: Beverley Talbott Date: Mon, 28 Jan 2013 12:52:41 +0100 Subject: [PATCH] DATACMNS-258 - Copyediting of reference documentation. --- src/docbkx/repositories.xml | 873 +++++++++--------- src/docbkx/repository-namespace-reference.xml | 8 +- .../repository-query-keywords-reference.xml | 18 +- 3 files changed, 477 insertions(+), 422 deletions(-) diff --git a/src/docbkx/repositories.xml b/src/docbkx/repositories.xml index d4c3c6c13..69b268a5a 100644 --- a/src/docbkx/repositories.xml +++ b/src/docbkx/repositories.xml @@ -2,50 +2,40 @@ - Repositories + Working with Spring Data Repositories -
- Introduction + The goal of Spring Data repository abstraction is to significantly + reduce the amount of boilerplate code required to implement data access + layers for various persistence stores. - 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 not designed in a real object oriented or - domain driven manner. + + Spring Data repository documentation and your + module - 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 in general for detailled - information on the specific features of a particular store consult the - later chapters of this document. - - - As this part of the documentation is pulled in from Spring Data - Commons we have to decide for a particular module to be used as example. - The configuration and code samples in this chapter are using the JPA - module. Make sure you adapt e.g. the XML namespace declaration, types to - be extended to the equivalents of the module you're actually - using. - -
+ This chapter explains the core concepts and interfaces of Spring + Data repositories. The information in this chapter is pulled from the + Spring Data Commons module. It uses the configuration and code samples for + the Java Persistence API (JPA) module. Adapt the XML namespace declaration + and the types to be extended to the equivalents of the particular module + that you are using. covers XML + configuration which is supported across all Spring Data modules supporting + the repository API, covers the + query method method keywords supported by the repository abstraction in + general. For detailed information on the specific features of your module, + consult the chapter on that module of this document. +
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. This interface mainly acts as marker interface - to capture the types to deal with and help us when discovering interfaces - that extend this one. Beyond that there's - CrudRepository which provides some - sophisticated functionality around CRUD for the entity being - managed. + surprise). It takes the the domain class to manage as well as the id type + of the domain class as type arguments. This interface acts primarily as a + marker interface to capture the types to work with and to help you to + discover interfaces that extend this one. The + CrudRepository provides sophisticated CRUD + functionality for the entity class that is being managed. <interfacename>CrudRepository</interfacename> interface @@ -105,7 +95,7 @@ - Returns whether an entity with the given id exists. + Indicates whether an entity with the given id exists. @@ -113,8 +103,11 @@ 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 this - interface. + implementations for a variety of Spring Data modules that implement + CrudRepository. + + On top of the CrudRepository there is a PagingAndSortingRepository abstraction @@ -123,15 +116,16 @@ PagingAndSortingRepository - public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> { + public interface PagingAndSortingRepository<T, ID extends Serializable> + extends CrudRepository<T, ID> { - Iterable<T> findAll(Sort sort); + Iterable<T> findAll(Sort sort); - Page<T> findAll(Pageable pageable); + Page<T> findAll(Pageable pageable); } - Pageable and its implementation PageRequest is 0 indexed, so accessing the second page of User by a page + Accessing the second page of User by a page size of 20 you could simply do something like this: PagingAndSortingRepository<User, Long> repository = // … get access to a bean @@ -141,15 +135,15 @@ Page<User> users = repository.findAll(new PageRequest(1, 20)); Query methods - Next to standard CRUD functionality repositories are usually queries - on the underlying datastore. With Spring Data declaring those queries - becomes a four-step process: + Standard CRUD functionality repositories usually have queries on the + underlying datastore. With Spring Data, declaring those queries becomes a + four-step process: Declare an interface extending - Repository or one of its sub-interfaces - and type it to the domain class it shall handle. + Repository or one of its subinterfaces + and type it to the domain class that it will handle. public interface PersonRepository extends Repository<User, Long> { … } @@ -161,7 +155,7 @@ Page<User> users = repository.findAll(new PageRequest(1, 20)); - Setup Spring to create proxy instances for those + Set up Spring to create proxy instances for those interfaces. <?xml version="1.0" encoding="UTF-8"?> @@ -178,11 +172,11 @@ Page<User> users = repository.findAll(new PageRequest(1, 20)); - Note that we use the JPA namespace here just by example. If - you're using the repository abstraction for any other store you need - to change this to the appropriate namespace declaration of your - store module which should be exchanging jpa in favor of - e.g. mongodb. + The JPA namespace is used in this example. If you are using + the repository abstraction for any other store, you need to change + this to the appropriate namespace declaration of your store module + which should be exchanging jpa in favor of, for + example, mongodb. @@ -196,38 +190,41 @@ Page<User> users = repository.findAll(new PageRequest(1, 20)); + } +} - 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 figure out details and various options - that you have at each stage. + The sections that follow explain each step.
Defining repository interfaces - As a very first step you define a domain class specific repository - interface. It's got to extend Repository - and be typed to the domain class and an ID type. If you want to expose - CRUD methods for that domain type, extend - CrudRepository instead of + As a first step you define a domain class-specific repository + interface. The interface must extend + Repository and be typed to the domain + class and an ID type. If you want to expose CRUD methods for that domain + type, extend CrudRepository instead of Repository.
- Fine tuning repository definition + Fine-tuning repository definition - Usually you will have your repository interface extend + Typically, your repository interface will extend Repository, CrudRepository or - PagingAndSortingRepository. If you - don't like extending Spring Data interfaces at all you can also - annotate your repository interface with - @RepositoryDefinition. Extending - CrudRepository will expose a complete - set of methods to manipulate your entities. If you would rather be - selective about the methods being exposed, simply copy the ones you + PagingAndSortingRepository. + Alternatively, if you do not want to extend Spring Data interfaces, + you can also annotate your repository interface with + @RepositoryDefinition. + Extending CrudRepository exposes a + complete set of methods to manipulate your entities. If you prefer to + be selective about the methods being exposed, simply copy the ones you want to expose from CrudRepository into your domain repository. @@ -245,72 +242,71 @@ interface UserRepository extends MyBaseRepository<User, Long> { } - In the first step we define a common base interface for all our - domain repositories and expose findOne(…) as - well as save(…).These methods will be routed - into the base repository implementation of the store of your choice - because they are matching the method signatures in - CrudRepository. So our + In this first step you defined a common base interface for all + your domain repositories and exposed + findOne(…) as well as + save(…).These methods will be routed into the + base repository implementation of the store of your choice provided by + Spring Data because they are matching the method signatures in + CrudRepository. So the UserRepository will now be able to save - users, find single ones by id as well as triggering a query to find - Users by their email address. + users, and find single ones by id, as well as triggering a query to + find Users by their email + address.
Defining query methods + The repository proxy has two ways to derive a store-specific query + from the method name. It can derive the query from the method name + directly, or by using an additionally created query. Available options + depend on the actual store. However, there's got to be an strategy that + decides what actual query is created. Let's have a look at the available + options. +
Query lookup strategies - The next thing we have to discuss is the definition of query - methods. There are two main ways that the repository proxy is able to - come up with the store specific query from the method name. The first - option is to derive the query 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 that decides what actual - query is created. - - There are three strategies available 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, It might be the - case that some of the strategies are not supported for specific - datastores. Here are your options: + The following strategies are available for the repository + infrastructure to resolve the query. You can configure the strategy at + the namespace through the query-lookup-strategy + attribute. Some strategies may not be supported for particular + datastores. 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 CREATE attempts to construct a store-specific + query from the query method 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 somewhere 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. + USE_DECLARED_QUERY tries to find a declared query + and will throw an exception in case it can't find one. The query can + be defined by an annotation somewhere or declared by other means. + Consult the documentation of the specific store to find available + options for that store. If the repository infrastructure does not + find a declared query for the method at bootstrap time, it + fails. CREATE_IF_NOT_FOUND (default) - This strategy is actually a combination of CREATE - and USE_DECLARED_QUERY. 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 the 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 as needed. + CREATE_IF_NOT_FOUND combines CREATE + and USE_DECLARED_QUERY. It looks up a declared query + first, and if no declared query is found, it creates a custom method + name-based query. This is the default lookup strategy and thus will + be used if you do not configure anything explicitly. It allows quick + query definition by method names but also custom-tuning of these + queries by introducing declared queries as needed.
@@ -318,15 +314,16 @@ interface UserRepository extends MyBaseRepository<User, Long> { Query creation The query builder mechanism built into Spring Data repository - infrastructure is useful to build constraining queries over entities - of the repository. We will strip the prefixes find…By, - read…By, as well as get…By from the method - and start parsing the rest of it. The introducing clause can contain - further expressions such as a Distinct to set a distinct - flag on the query to be created. However, the first By - acts as delimiter to indicate the start of the actual criterias. At a - very basic level you can define conditions on entity properties and - concatenate them with AND and OR. + infrastructure is useful for building constraining queries over + entities of the repository. The mechanism strips the prefixes + find…By, read…By, and get…By + from the method and starts parsing the rest of it. The introducing + clause can contain further expressions such as a Distinct + to set a distinct flag on the query to be created. However, the first + By acts as delimiter to indicate the start of the actual + criteria. At a very basic level you can define conditions on entity + properties and concatenate them with And and Or + . Query creation from method names @@ -350,84 +347,101 @@ interface UserRepository extends MyBaseRepository<User, Long> { } - 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 expressions 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 also 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. + The actual result of parsing the method depends on the + persistence store for which you create the query. However, there are + some general things to notice. + + The expressions are usually property traversals combined + with operators that can be concatenated. You can combine + property expressions with AND and OR. + You also get support for operators such as + Between, LessThan, + GreaterThan, Like for the + property expressions. The supported operators can vary by + datastore, so consult the appropriate part of your reference + documentation. + - As you can see the method parser also supports setting an ignore - case flag for individual properties (e.g. - findByLastnameIgnoreCase(…)) or for all - properties of a type that support ignoring case (i.e. usually - Strings, e.g. - findByLastnameAndFirstnameAllIgnoreCase(…)). - Whether ignoring cases is supported my differ from store to store, so - consult the relevant sections of the store specific query method - reference docs. + + The method parser supports setting an + IgnoreCase flag for individual properties, for + example,findByLastnameIgnoreCase(…)) or + for all properties of a type that support ignoring case (usually + Strings, for example, + findByLastnameAndFirstnameAllIgnoreCase(…)). + Whether ignoring cases is supported may vary by store, so + consult the relevant sections in the reference documentation for + the store-specific query method. + - Static ordering can be applied by appending an - OrderBy clause to the query method referencing a property - and providing a sorting direction (Asc or - Desc). To create a query method that supports dynamic - sorting have a look at . + + You can apply static ordering by appending an + OrderBy clause to the query method that references + a property and by providing a sorting direction + (Asc or Desc). To create a query + method that supports dynamic sorting, see . + + +
-
- Property expressions +
+ 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 define - constraints by traversing nested properties. Assume - Persons have Addresses - with ZipCodes. In that case a method name - of + Property expressions can refer only to a direct property of the + managed entity, as shown in the preceding example. At query creation + time you already make sure that the parsed property is a property of + the managed domain class. However, you can also define constraints by + traversing nested properties. Assume Persons + have Addresses with + ZipCodes. In that case a method name of - List<Person> findByAddressZipCode(ZipCode zipCode); + 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). + creates the property traversal x.address.zipCode. + The resolution algorithm starts with interpreting the entire part + (AddressZipCode) as the property and checks the + domain class for a property with that name (uncapitalized). If the + algorithm succeeds it uses that property. If not, the algorithm splits + up the source at the camel case parts from the right side into a head + and a tail and tries to find the corresponding property, in our + example, AddressZip and Code. If + the algorithm finds a property with that head it takes the tail and + continue building the tree down from there, splitting the tail up in + the way just described. If the first split does not match, the + algorithm move the split point to the left + (Address, ZipCode) and + continues. - Although this should work for most cases, there might be cases - where the algorithm could select the wrong property. Suppose our - Person class has an 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: + Although this should work for most cases, it is possible for the + algorithm to select the wrong property. Suppose the + Person class has an addressZip + property as well. The 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 the examples above. Besides that we will - recognizes certain specific types to apply pagination and sorting to - your queries dynamically. + To handle parameters to your query you simply define method + parameters as already seen in the examples above. Besides that the + infrastructure will recognize certain specific types like + Pageable and + Sort to apply pagination and sorting to your + queries dynamically. Using Pageable and Sort in query methods @@ -439,23 +453,25 @@ List<User> findByLastname(String lastname, Sort sort); List<User> findByLastname(String lastname, Pageable pageable); - The first method allows you to pass a + The first method allows you to pass an org.springframework.data.domain.Pageable instance to the query method to dynamically add paging to your statically defined - query. Sorting options are handed via the + query. Sorting options are handled through the Pageable instance too. If you only need sorting, simply add an org.springframework.data.domain.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. + List is possible as well. In this case + the additional metadata required to build the actual + Page instance will not be created + (which in turn means that the additional count query that would have + been necessary not being issued) but rather simply restricts the query + to look up 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. + To find out how many pages you get for a query entirely you + have to trigger an additional count query. By default this query + will be derived from the query you actually trigger.
@@ -463,16 +479,16 @@ List<User> findByLastname(String lastname, Pageable pageable); Creating repository instances - So now the question is how to create instances and bean - definitions for the repository interfaces defined. + In this section you create instances and bean definitions for the + repository interfaces defined. 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.
- XML Configuration + XML configuration - 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 package that Spring will scan for + Each Spring Data module includes a repositories element that + allows you to simply define a base package that Spring scans for you. <?xml version="1.0" encoding="UTF-8"?> @@ -488,40 +504,38 @@ List<User> findByLastname(String lastname, Pageable pageable); - In this case we instruct Spring to scan - com.acme.repositories and all its sub packages for + In the preceding example, Spring is instructed to scan + com.acme.repositories and all its subpackages for interfaces extending Repository or one - of its sub-interfaces. For each interface found it will register the - persistence 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 the use of wildcards, so that you can have a pattern - of scanned packages. + of its subinterfaces. For each interface found, the infrastructure + registers the persistence technology-specific + FactoryBean to create the appropriate + proxies that handle invocations of the query methods. Each bean is + 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 wildcards, so that you can + have a pattern of scanned packages. 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 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 By default the infrastructure picks up every interface + extending the persistence technology-specific + Repository subinterface located under + the configured base package and creates a bean instance for it. + However, you might want more fine-grained control over which + interfaces bean instances get created for. To do this you use + <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: + For example, to exclude certain interfaces from instantiation + as repository, you could use the following configuration: Using exclude-filter element @@ -530,7 +544,7 @@ List<User> findByLastname(String lastname, Pageable pageable); - This would exclude all interfaces ending in + This example excludes all interfaces ending in SomeRepository from being instantiated. @@ -543,15 +557,15 @@ List<User> findByLastname(String lastname, Pageable pageable);The repository infrastructure can also be triggered using a store-specific @Enable${store}Repositories annotation - on a JavaConfig class. For an introduction into Java based - configuration of the Spring container please have a look at the - reference documentation. + on a JavaConfig class. For an introduction into Java-based + configuration of the Spring container, see the reference + documentation. JavaConfig in the Spring reference documentation - - A sample configuration to enable Spring Data repositories would - look something like this. + A sample configuration to enable Spring Data repositories looks + something like this. Sample annotation based repository configuration @@ -567,23 +581,25 @@ class ApplicationConfiguration { } - Note that the sample uses the JPA specific annotation which - would have to be exchanged dependingon which store module you actually - use. The same applies to the definition of the - EntityManagerFactory bean. Please - consult the sections covering the store-specific configuration. + + The sample uses the JPA-specific annotation, which you would + change according to the store module you actually use. The same + applies to the definition of the + EntityManagerFactory bean. Consult + the sections covering the store-specific configuration. +
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 - programmatically as well. The Spring Data modules providing repository - support ship a persistence technology specific - RepositoryFactory that can be used as - follows: + Spring container. You still need some Spring libraries in your + classpath, but generally you can set up repositories programmatically + as well. The Spring Data modules that provide repository support ship + a persistence technology-specific + RepositoryFactory that you can use as + follows. Standalone usage of repository factory @@ -596,18 +612,19 @@ UserRepository repository = factory.getRepository(UserRepository.class);
- Custom implementations + Custom implementations for Spring Data repositories + + Often it is necessary to provide a custom implementation for a few + repository methods. Spring Data repositories easily allow you to provide + custom repository code and integrate it with generic CRUD abstraction and + query method functionality.
- Adding behaviour to single repositories + Adding custom behavior to single repositories - Often it is necessary to provide a custom implementation for a few - repository methods. Spring Data repositories easily allow you to 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. + To enrich a repository with custom functionality you first define + an interface and an implementation for the custom functionality. Use the + repository interface you provided to extend the custom interface. Interface for custom repository functionality @@ -626,10 +643,12 @@ UserRepository repository = factory.getRepository(UserRepository.class);Note that the implementation itself does not depend on - Spring Data and can be a regular Spring bean. So you can use standard - dependency injection behaviour to inject references to other beans, - take part in aspects and so on. +} + The implementation itself does not depend on Spring Data and + can be a regular Spring bean. So you can use standard dependency + injection behavior to inject references to other beans, take part + in aspects, and so on. + @@ -639,19 +658,20 @@ UserRepository repository = factory.getRepository(UserRepository.class);Let your standard repository interface extend the custom - one. This makes CRUD and custom functionality available to + one. Doing so 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. + If you use namespace configuration, the repository + infrastructure tries to autodetect custom implementations by scanning + for classes below the package we found a repository in. These classes + need to follow the naming convention of appending the namespace + element's attribute repository-impl-postfix to the found + repository interface name. This postfix defaults to + Impl. Configuration example @@ -661,7 +681,7 @@ UserRepository repository = factory.getRepository(UserRepository.class); - The first configuration example will try to lookup a class + The first configuration example will try to look up a class com.acme.repository.UserRepositoryImpl to act as custom repository implementation, where the second example will try to lookup @@ -671,13 +691,13 @@ UserRepository repository = factory.getRepository(UserRepository.class); Manual wiring - The approach above works perfectly well if your custom - implementation uses annotation based configuration and autowiring - entirely as it will be treated as any other Spring bean. If your - custom implementation bean needs some special wiring you simply - declare the bean and name it after the conventions just described. We - will then pick up the custom bean by name rather than creating an - instance. + The preceding approach works well if your custom implementation + uses annotation-based configuration and autowiring only, as it will be + treated as any other Spring bean. If your custom implementation bean + needs special wiring, you simply declare the bean and name it after + the conventions just described. The infrastructure will then refer to + the manually defined bean definition by name instead of creating one + itself. Manual wiring of custom implementations (I) @@ -692,52 +712,43 @@ UserRepository repository = factory.getRepository(UserRepository.class);
- Adding custom behaviour to all repositories + Adding custom behavior 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 + The preceding approach is not feasible when you want to add a + single method to all your repository interfaces. - - An interface declaring custom shared behaviour + + + To add custom behavior to all repositories, you first add an + intermediate interface to declare the shared behavior. - + + An interface declaring custom shared behavior + + 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 instead of the - Repository 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 then act as a custom base class for the - repository proxies. + Now your individual repository interfaces will extend this + intermediate interface instead of the + Repository interface to include the + functionality declared. + - - The default behaviour of the Spring <repositories - /> namespace is to provide an implementation for all - interfaces that fall under the base-package. This means - that if left in it's current state, an implementation instance of - MyRepository will be created by Spring. - This is of course not desired as it is just supposed to act as an - intermediary between Repository and the - actual repository interfaces you want to define for each entity. To - exclude an interface extending - Repository from being instantiated as a - repository instance it can either be annotate it with - @NoRepositoryBean or moved out side of - the configured base-package. - + + Next, create an implementation of the intermediate interface + that extends the persistence technology-specific repository base + class. This class will then act as a custom base class for the + repository proxies. - - Custom repository base class + + Custom repository base class - + public class MyRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> { @@ -755,21 +766,37 @@ public class MyRepositoryImpl<T, ID extends Serializable> // implementation goes here } } - + - The last step is to create a custom repository factory to replace - the default RepositoryFactoryBean that will in - turn produce a custom RepositoryFactory. The new - repository factory will then provide your - MyRepositoryImpl as the implementation of any - interfaces that extend the Repository - interface, replacing the SimpleJpaRepository - implementation you just extended. + The default behavior of the Spring <repositories + /> namespace is to provide an implementation for all + interfaces that fall under the base-package. This means + that if left in its current state, an implementation instance of + MyRepository will be created by + Spring. This is of course not desired as it is just supposed to act + as an intermediary between Repository + and the actual repository interfaces you want to define for each + entity. To exclude an interface that extends + Repository from being instantiated as + a repository instance, you can either annotate it with + @NoRepositoryBean or move it outside + of the configured base-package. + - - Custom repository factory bean + + Then create a custom repository factory to replace the default + RepositoryFactoryBean that will in turn + produce a custom RepositoryFactory. The new + repository factory will then provide your + MyRepositoryImpl as the implementation of any + interfaces that extend the Repository + interface, replacing the SimpleJpaRepository + implementation you just extended. - + + Custom repository factory bean + + public class MyRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> { @@ -801,37 +828,41 @@ public class MyRepositoryFactoryBean<R extends JpaRepository<T, I>, T, } } } - + + - 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. + + Finally, 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 + + Using the custom factory with the namespace - <repositories base-package="com.acme.repository" + <repositories base-package="com.acme.repository" factory-class="com.acme.MyRepositoryFactoryBean" /> - + + +
- Extensions + Spring Data extensions - This chapter documents a set of Spring Data extensions that enable + This section documents a set of Spring Data extensions that enable Spring Data usage in a variety of contexts. Currently most of the integration is targeted towards Spring MVC.
Domain class web binding for Spring MVC - Given you are developing a Spring MVC web applications you - typically have to resolve domain class ids from URLs. By default it's - your task to transform that request parameter or URL part into the - domain class to hand it layers below then or execute business logic on - the entities directly. This should look something like this: + Given you are developing a Spring MVC web application you + typically have to resolve domain class ids from URLs. By default your + task is to transform that request parameter or URL part into the domain + class to hand it to layers below then or execute business logic on the + entities directly. This would look something like this: @Controller @RequestMapping("/users") @@ -857,24 +888,24 @@ public class UserController { } } - First you pretty much have to declare a repository dependency for - each controller to lookup the entity managed by the controller or - repository respectively. Beyond that looking up the entity is - boilerplate as well as it's always a findOne(…) - call. Fortunately Spring provides means to register custom converting - components that allow conversion between a String - value to an arbitrary type. + First you declare a repository dependency for each controller to + look up the entity managed by the controller or repository respectively. + Looking up the entity is boilerplate as well, as it's always a + findOne(…) call. Fortunately Spring provides + means to register custom components that allow conversion between a + String value to an arbitrary type. PropertyEditors - For versions up to Spring 3.0 simple Java - PropertyEditors had to be used. Thus, - we offer a DomainClassPropertyEditorRegistrar, - that will look up all Spring Data repositories registered in the - ApplicationContext and register a + For Spring versions before 3.0 simple Java + PropertyEditors had to be used. To + integrate with that, Spring Data offers a + DomainClassPropertyEditorRegistrar, which looks + up all Spring Data repositories registered in the + ApplicationContext and registers a custom PropertyEditor for the managed - domain class + domain class. <bean class="….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="webBindingInitializer"> @@ -886,9 +917,9 @@ public class UserController { </property> </bean> - If you have configured Spring MVC like this you can turn your - controller into the following that reduces a lot of the clutter and - boilerplate. + If you have configured Spring MVC as in the preceding example, + you can configure your controller as follows, which reduces a lot of + the clutter and boilerplate. @Controller @RequestMapping("/users") @@ -906,16 +937,15 @@ public class UserController { ConversionService - As of Spring 3.0 the - PropertyEditor support is superseeded - by a new conversion infrstructure that leaves all the drawbacks of - PropertyEditors behind and uses a - stateless X to Y conversion approach. We now ship with a - DomainClassConverter that pretty much mimics - the behaviour of - DomainClassPropertyEditorRegistrar. To + In Spring 3.0 and later the + PropertyEditor support is superseded by + a new conversion infrastructure that eliminates the drawbacks of + PropertyEditors and uses a stateless X + to Y conversion approach. Spring Data now ships with a + DomainClassConverter that mimics the behavior + of DomainClassPropertyEditorRegistrar. To configure, simply declare a bean instance and pipe the - ConversionService being used into it's + ConversionService being used into its constructor: <mvc:annotation-driven conversion-service="conversionService" /> @@ -924,10 +954,10 @@ public class UserController { <constructor-arg ref="conversionService" /> </bean> - If you're using JavaConfig you can simply extend + If you are using JavaConfig, you can simply extend Spring MVC's WebMvcConfigurationSupport and hand the - FormatingConversionService the configuration - superclass provides into the + FormatingConversionService that the + configuration superclass provides into the DomainClassConverter instance you create. @@ -946,6 +976,14 @@ public class UserController {
Web pagination + When working with pagination in the web layer you usually have to + write a lot of boilerplate code yourself to extract the necessary + metadata from the request. The less desirable approach shown in the + example below requires the method to contain an + HttpServletRequest parameter that has to + be parsed manually. This example also omits appropriate failure + handling, which would make the code even more verbose. + @Controller @RequestMapping("/users") public class UserController { @@ -965,14 +1003,10 @@ public class UserController { } } - As you can see the naive approach requires the method to contain - an HttpServletRequest parameter that has - to be parsed manually. We even omitted an appropriate failure handling - which would make the code even more verbose. The bottom line is that the - controller actually shouldn't have to handle the functionality of - extracting pagination information from the request. So we include a - PageableArgumentResolver that will do the work - for you. + The bottom line is that the controller should not have to handle + the functionality of extracting pagination information from the request. + So Spring includes a PageableArgumentResolver + that will do the work for you. <bean class="….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="customArgumentResolvers"> @@ -997,10 +1031,10 @@ public class UserController { } } - The PageableArgumentResolver will - automatically resolve request parameters to build a - PageRequest instance. By default it will expect - the following structure for the request parameters: + The PageableArgumentResolver automatically + resolves request parameters to build a + PageRequest instance. By default it expects the + following structure for the request parameters. Request parameters evaluated by @@ -1013,63 +1047,67 @@ public class UserController { <tbody> <row> - <entry><code>page.page</code></entry> + <entry><code>page</code></entry> - <entry>The page you want to retrieve</entry> + <entry>Page you want to retrieve.</entry> </row> <row> <entry><code>page.size</code></entry> - <entry>The size of the page you want to retrieve</entry> + <entry>Size of the page you want to retrieve.</entry> </row> <row> <entry><code>page.sort</code></entry> - <entry>The property that should be sorted by</entry> + <entry>Property that should be sorted by.</entry> </row> <row> <entry><code>page.sort.dir</code></entry> - <entry>The direction that should be used for sorting</entry> + <entry>Direction that should be used for sorting.</entry> </row> </tbody> </tgroup> </table> <para>In case you need multiple <interfacename>Pageable</interfacename>s - to be resolved from the request (for multiple tables e.g.) you can use - Spring's <interfacename>@Qualifier</interfacename> annotation to + to be resolved from the request (for multiple tables, for example) you + can use Spring's <interfacename>@Qualifier</interfacename> annotation to distinguish one from another. The request parameters then have to be - prefixed with <code>${qualifier}_</code>. So a method signature like + prefixed with <code>${qualifier}_</code>. So for a method signature like this:</para> <programlisting lang="" language="java">public String showUsers(Model model, @Qualifier("foo") Pageable first, - @Qualifier("bar") Pageable second) { … } -</programlisting> + @Qualifier("bar") Pageable second) { … }</programlisting> - <para>you'd have to populate <code>foo_page</code> and - <code>bar_page</code> and the according subproperties.</para> + <para>you have to populate <code>foo_page</code> and + <code>bar_page</code> and the related subproperties.</para> <simplesect> - <title>Defaulting + Configuring a global default on bean declarationThe PageableArgumentResolver will use a PageRequest with the first page and a page size - of 10 by default and will use that in case it can't resolve a + of 10 by default. It will use that value if it cannot resolve a PageRequest from the request (because of - missing parameters e.g.). You can configure a global default on the - bean declaration directly. In case you might need controller method - specific defaults for the Pageable - simply annotate the method parameter with + missing parameters, for example). You can configure a global default + on the bean declaration directly. If you might need controller method + specific defaults for the Pageable, + annotate the method parameter with @PageableDefaults and specify page (through pageNumber), page size (through - value) as well as sort (the list of - properties to sort by) as wel as sortDir (the direction - to sort by) as annotation attributes: + value), sort (list of properties to sort + by), and sortDir (the direction to sort by) as annotation + attributes:public String showUsers(Model model, @PageableDefaults(pageNumber = 0, value = 30) Pageable pageable) { … } @@ -1079,13 +1117,13 @@ public class UserController {
Repository populators - If you have been working with the JDBC module of Spring you're - probably familiar with the support to populate a DataSource using SQL - scripts. A similar abstraction is available on the repositories level - although we don't use SQL as data definition language as we need to be - store independent of course. Thus the populators support XML (through - Spring's OXM abstraction) and JSON (through Jackson) to define data for - the repositories to be populated with. + If you work with the Spring JDBC module, you probably are familiar + with the support to populate a DataSource + using SQL scripts. A similar abstraction is available on the + repositories level, although it does not use SQL as the data definition + language because it must be store-independent. Thus the populators + support XML (through Spring's OXM abstraction) and JSON (through + Jackson) to define data with which to populate the repositories. Assume you have a file data.json with the following content: @@ -1101,11 +1139,11 @@ public class UserController { "lastname" : "Beauford" } ] - You can easily populate you repositories by using the populator + You can easily populate your repositories by using the populator elements of the repository namespace provided in Spring Data Commons. To - get the just shown data be populated to your - PersonRepository all you need to do is - the following: + populate the preceding data to your + PersonRepository , do the + following: Declaring a Jackson repository populator @@ -1124,16 +1162,21 @@ public class UserController { </beans> - This declaration causes the data.json file being read, - deserialized by a Jackson ObjectMapper. The type - the JSON object will be unmarshalled to will be determined by inspecting - the _class attribute of the JSON document. We will - eventually select the appropriate repository being able to handle the - object just deserialized. + This declaration causes the data.json file + being read, deserialized by a Jackson + ObjectMapper. The type to which the JSON object will be unmarshalled to will + be determined by inspecting the _class attribute of the + JSON document. The infrastructure will eventually select the appropriate + repository to handle the object just deserialized. + + To rather use XML to define the data the repositories shall be + populated with, you can use the unmarshaller-populator + element. You configure it to use one of the XML marshaller options + Spring OXM provides you with. See the Spring reference + documentation for details. Declaring an unmarshalling repository populator (using diff --git a/src/docbkx/repository-namespace-reference.xml b/src/docbkx/repository-namespace-reference.xml index 76e44198c..f3345073e 100644 --- a/src/docbkx/repository-namespace-reference.xml +++ b/src/docbkx/repository-namespace-reference.xml @@ -7,9 +7,9 @@ <section id="namespace-dao-config"> <title>The <code><repositories /></code> element - The <repositories /> triggers the setup of the - Spring Data repository infrastructure. The most important attribute is - base-package which defines the package to scan for Spring + The <repositories /> element triggers the setup + of the Spring Data repository infrastructure. The most important attribute + is base-package which defines the package to scan for Spring Data repository interfaces. see @@ -39,7 +39,7 @@ interfaces extending *Repository (actual interface is determined by specific Spring Data module) in auto detection mode. All packages below the configured package - will be scanned, too. Wildcards are also allowed. + will be scanned, too. Wildcards are allowed. diff --git a/src/docbkx/repository-query-keywords-reference.xml b/src/docbkx/repository-query-keywords-reference.xml index d00f0df78..796e61eb3 100644 --- a/src/docbkx/repository-query-keywords-reference.xml +++ b/src/docbkx/repository-query-keywords-reference.xml @@ -8,9 +8,9 @@ Supported query keywords The following table lists the keywords generally supported by the - Spring data repository query derivation mechanism. However consult the - store specific documentation for the exact list of supported keywords as - some of the ones listed here might not be supported in a particular + Spring Data repository query derivation mechanism. However, consult the + store-specific documentation for the exact list of supported keywords, + because some listed here might not be supported in a particular store.
@@ -30,6 +30,18 @@ + + AND + + And + + + + OR + + Or + + AFTER