diff --git a/pom.xml b/pom.xml
index c2972dae5..2ea00357f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
1.0.0.BUILD-SNAPSHOTjar2012
- http://github.com/biomedcentral/spring-data-elasticsearch
+ https://github.com/BioMedCentralLtd/spring-data-elasticsearchSpring Data ElasticsearchSpring Data module providing support for Elasticsearch repositories
@@ -56,10 +56,6 @@
-
https://github.com/biomedcentral/spring-data-elasticsearch
@@ -68,10 +64,10 @@
-
+
+ Travis
+ https://travis-ci.org/BioMedCentralLtd/spring-data-elasticsearch
+
@@ -312,7 +308,7 @@
-
-
-
-
-
+
+
+ distribute
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.8
+
+
+
+ javadoc
+
+ package
+
+
+
+ true
+ Spring Data Elasticsearch
+ ${project.version}
+ true
+
+ true
+
+ http://static.springframework.org/spring/docs/3.1.x/javadoc-api
+ http://download.oracle.com/javase/1.5.0/docs/api
+ http://static.springsource.org/spring-data/data-commons/docs/${spring.data-commons.version}/api
+
+
+
+
+ com.agilejava.docbkx
+ docbkx-maven-plugin
+ 2.0.7
+
+
+
+ generate-html
+ generate-pdf
+
+ package
+
+
+
+
+ org.docbook
+ docbook-xml
+ 4.4
+ runtime
+
+
+
+ index.xml
+ true
+ ${project.basedir}/src/docbkx/resources/xsl/fopdf.xsl
+ css/html.css
+ false
+ ${project.basedir}/src/docbkx/resources/xsl/html.xsl
+ 1
+ 1
+
+
+ version
+ ${project.version}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ maven-assembly-plugin
+ 2.2.1
+
+
+ distribution
+
+ single
+
+ package
+
+
+ ${project.basedir}/src/main/assembly/distribution.xml
+
+ false
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ biomedcentral
+ BioMed Central Development Team
+ +0
+
+
-
-
-
-
-
-
diff --git a/src/docbkx/index.xml b/src/docbkx/index.xml
index 57fb60946..14690c759 100644
--- a/src/docbkx/index.xml
+++ b/src/docbkx/index.xml
@@ -3,25 +3,17 @@
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
- Spring Data Solr
+ Spring Data Elasticsearch
- Christoph
- Strobl
+ Rizwan
+ Idrees
- Oliver
- Gierke
+ Mohsin
+ Husen
-
- Mark
- Pollack
-
-
- Thomas
- Risberg
-
-
+
Copies of this document may be made for your own use and for
@@ -35,7 +27,7 @@
- 2012
+ 2013The original author(s)
@@ -51,7 +43,7 @@
-
+
diff --git a/src/docbkx/preface.xml b/src/docbkx/preface.xml
index 056adf7e2..e9d859e59 100644
--- a/src/docbkx/preface.xml
+++ b/src/docbkx/preface.xml
@@ -3,13 +3,13 @@
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
Preface
- The Spring Data Solr project applies core Spring concepts to
+ The Spring Data Elasticsearch project applies core Spring concepts to
the
- development of solutions using the Apache Solr Search Engine.
- We
- provide a "template" as a high-level abstraction for storing and
- querying documents. You will notice similarities to the mongodb
- support in the Spring Framework.
+ development of solutions using the Elasticsearch Search Engine.
+ We have povided a "template" as a high-level abstraction for
+ storing,querying,sorting and faceting documents. You will notice similarities
+ to the Spring data solr and
+ mongodb support in the Spring Framework.
Project Metadata
@@ -17,56 +17,18 @@
Version Control -
- git://github.com/SpringSource/spring-data-solr.git
+ git://github.com/BioMedCentralLtd/spring-data-elasticsearch.git
-
-
- Bugtacker -
- https://jira.springsource.org/browse/DATASOLR
-
-
-
-
-
- Release repository -
- http://repo.springsource.org/libs-release
-
-
-
-
-
- Milestone repository -
- http://repo.springsource.org/libs-milestone
-
-
-
-
-
- Snapshot repository -
- http://repo.springsource.org/libs-snapshot
-
- Requirements
Requires
- Apache Solr
- 3.5 and above or optional dependency
- <dependency>
- <groupId>org.apache.solr</groupId>
- <artifactId>solr-core</artifactId>
- <version>${solr.version}</version>
-</dependency>
-
- If you tend to use the Embedded Version of Solr
- Server 4.x you will also have to add a version of servlet-api and
- check your <lockType> as well as <unlockOnStartup>
- settings.
-
-
+ Elasticsearch
+ 0.20.2 and above or optional dependency
+
\ No newline at end of file
diff --git a/src/docbkx/reference/data-elasticsearch.xml b/src/docbkx/reference/data-elasticsearch.xml
new file mode 100644
index 000000000..7a9f573f7
--- /dev/null
+++ b/src/docbkx/reference/data-elasticsearch.xml
@@ -0,0 +1,599 @@
+
+
+
+ Solr Repositories
+
+ This chapter includes details of the Solr repository
+ implementation.
+
+
+
+ Introduction
+
+
+ Spring Namespace
+
+
+ The Spring Data Elasticsearch module contains a custom namespace allowing
+ definition of repository beans as well as elements for instantiating
+ a
+ ElasticsearchServer
+ .
+
+
+
+ Using the
+ repositories
+ element looks up Spring Data repositories as described in
+
+ .
+
+
+
+ Setting up Elasticsearch repositories using Namespace
+ <?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/data/elasticsearch
+ http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
+
+ <elasticsearch:repositories base-package="com.acme.repositories" />
+</beans>
+
+
+
+ Using the
+ Transport Client
+ or
+ Node Client
+ element registers an instance of
+ Elasticsearch Server
+ in the context.
+
+
+ Transport Client using Namespace
+ <?xml version="1.0" encoding="UTF-8"?>
+ <beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/data/elasticsearch
+ http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
+
+ <elasticsearch:transport-client id="client" cluster-nodes="localhost:9300,someip:9300" />
+</beans>
+
+
+
+ Node Client using Namespace
+ <?xml version="1.0" encoding="UTF-8"?>
+ <beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/data/elasticsearch
+ http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
+
+ <elasticsearch:node-client id="client" local="true"" />
+</beans>
+
+
+
+
+ Annotation based configuration
+ The Spring Data Elasticsearch repositories support cannot only be
+ activated through an XML namespace but also using an annotation
+ through JavaConfig.
+
+
+ Spring Data Elasticsearch repositories using JavaConfig
+ @Configuration
+ @EnableElasticsearchRepositories(basePackages = "org/springframework/data/elasticsearch/repositories")
+ static class Config {
+
+ @Bean
+ public ElasticsearchOperations elasticsearchTemplate() {
+ return new ElasticsearchTemplate(nodeBuilder().local(true).node().client());
+ }
+ }
+
+ The configuration above sets up an
+ Embedded Elasticsearch Server
+ which is used by the
+ ElasticsearchTemplate
+ . Spring Data Elasticsearch Repositories are activated using the
+ @EnableElasticsearchRepositories
+ annotation, which
+ essentially carries the same attributes as the XML
+ namespace does. If no
+ base package is configured, it will use the
+ one
+ the configuration class
+ resides in.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Query methods
+
+ Query lookup strategies
+
+ The Elasticsearch module supports all basic query building feature as String,Abstract,Criteria or
+ have
+ it being derived from the method name.
+
+ There is no QueryDSL Support present at this time.
+
+
+
+
+ Declared queries
+
+ Deriving the query from the method name is not always sufficient
+ and/or may result in unreadable method names. In this case one
+ might make either use of Elasticsearch named queries (see
+
+ ) or use the
+ @Query
+ annotation (see
+
+ ).
+
+
+
+
+
+ Query creation
+
+
+ Generally the query creation mechanism for Elasticsearch works as described
+ in
+
+ . Here's a short example
+ of what a Elasticsearch query method translates into:
+
+ Query creation from method names
+ public interface BookRepository extends Repository<Book, String> {
+ List<Book> findByNameAndPrice(String name, Integer price);
+}
+
+ The method name above will be translated into the following
+ Elasticsearch json query
+
+ {
+ "bool" : {
+ "must" : [ {
+ "field" : {
+ "type" : "test"
+ }
+ }, {
+ "field" : {
+ "message" : "some message"
+ }
+ } ]
+ }
+ }
+
+
+
+ A list of supported keywords for Elasticsearch is shown below.
+
+
+
+
+ Using @Query Annotation
+
+ Using named queries (
+
+ ) to declare queries for entities is a valid
+ approach and works fine
+ for a small number of queries. As the
+ queries themselves are tied to
+ the Java method that executes them,
+ you actually can bind them
+ directly using the Spring Data Solr
+ @Query
+ annotation.
+
+
+
+ Declare query at the method using the
+ @Query
+ annotation.
+
+
+ public interface ProductRepository extends SolrRepository<Product, String> {
+ @Query("inStock:?0")
+ List<Product> findByAvailable(Boolean available);
+}
+
+
+
+ Using NamedQueries
+
+ Named queries can be kept in a properties file and wired to the
+ accroding method. Please mind the naming convention described in
+
+ or use
+ @Query
+ .
+
+
+
+ Declare named query in properites file
+
+ Product.findByNamedQuery=popularity:?0
+Product.findByName=name:?0
+ public interface ProductRepository extends SolrCrudRepository<Product, String> {
+
+ List<Product> findByNamedQuery(Integer popularity);
+
+ @Query(name = "Product.findByName")
+ List<Product> findByAnnotatedNamedQuery(String name);
+
+}
+
+
+
+
\ No newline at end of file
diff --git a/src/docbkx/reference/data-solr.xml b/src/docbkx/reference/data-solr.xml
deleted file mode 100644
index a5659e0ad..000000000
--- a/src/docbkx/reference/data-solr.xml
+++ /dev/null
@@ -1,501 +0,0 @@
-
-
-
- Solr Repositories
-
- This chapter includes details of the Solr repository
- implementation.
-
-
-
- Introduction
-
-
- Spring Namespace
-
-
- The Spring Data Solr module contains a custom namespace allowing
- definition of repository beans as well as elements for instantiating
- a
- SolrServer
- .
-
-
-
- Using the
- repositories
- element looks up Spring Data repositories as described in
-
- .
-
-
-
- Setting up Solr repositories using Namespace
- <?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:solr="http://www.springframework.org/schema/data/solr"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/data/solr
- http://www.springframework.org/schema/data/solr/spring-solr-1.0.xsd">
-
- <solr:repositories base-package="com.acme.repositories" />
-</beans>
-
-
-
- Using the
- solr-server
- or
- embedded-solr-server
- element registers an instance of
- SolrServer
- in the context.
-
-
- HttpSolrServer using Namespace
- <?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:solr="http://www.springframework.org/schema/data/solr"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/data/solr
- http://www.springframework.org/schema/data/solr/spring-solr-1.0.xsd">
-
- <solr:solr-server id="solrServer" url="http://locahost:8983/solr" />
-</beans>
-
-
-
- EmbeddedSolrServer using Namespace
- <?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:solr="http://www.springframework.org/schema/data/solr"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/data/solr
- http://www.springframework.org/schema/data/solr/spring-solr-1.0.xsd">
-
- <solr:embedded-solr-server id="solrServer" solrHome="classpath:com/acme/solr" />
-</beans>
-
-
-
-
- Annotation based configuration
- The Spring Data Solr repositories support cannot only be
- activated through an XML namespace but also using an annotation
- through JavaConfig.
-
-
- Spring Data Solr repositories using JavaConfig
- @Configuration
-@EnableSolrRepositories
-class ApplicationConfig {
-
- @Bean
- public SolrServer solrServer() {
- EmbeddedSolrServerFactory factory = new EmbeddedSolrServerFactory("classpath:com/acme/solr");
- return factory.getSolrServer();
- }
-
- @Bean
- public SolrOperations solrTemplate() {
- return new SolrTemplate(solrServer());
- }
-}
-
- The configuration above sets up an
- EmbeddedSolrServer
- which is used by the
- SolrTemplate
- . Spring Data Solr Repositories are activated using the
- @EnableSolrRepositories
- annotation, which
- essentially carries the same attributes as the XML
- namespace does. If no
- base package is configured, it will use the
- one
- the configuration class
- resides in.
-
-
-
-
- Solr Repositores using CDI
- The Spring Data Solr repositories can also be set up using CDI
- functionality.
-
-
- Spring Data Solr repositories using JavaConfig
- class SolrTemplateProducer {
-
- @Produces
- @ApplicationScoped
- public SolrOperations createSolrTemplate() {
- return new SolrTemplate(new EmbeddedSolrServerFactory("classpath:com/acme/solr"));
- }
-}
-
-class ProductService {
-
- private ProductRepository repository;
-
- public Page<Product> findAvailableProductsByName(String name, Pageable pageable) {
- return repository.findByAvailableTrueAndNameStartingWith(name, pageable);
- }
-
- @Inject
- public void setRepository(ProductRepository repository) {
- this.repository = repository;
- }
-}
-
-
-
-
- Query methods
-
- Query lookup strategies
-
- The Solr module supports defining a query manually as String or
- have
- it being derived from the method name.
-
- There is no QueryDSL Support present at this time.
-
-
-
-
- Declared queries
-
- Deriving the query from the method name is not always sufficient
- and/or may result in unreadable method names. In this case one
- might make either use of Solr named queries (see
-
- ) or use the
- @Query
- annotation (see
-
- ).
-
-
-
-
-
- Query creation
-
-
- Generally the query creation mechanism for Solr works as described
- in
-
- . Here's a short example
- of what a Solr query method translates into:
-
- Query creation from method names
- public interface ProductRepository extends Repository<Product, String> {
- List<Product> findByNameAndPopularity(String name, Integer popularity);
-}
-
- The method name above will be translated into the following
- solr query
-
- q=name:?0 AND popularity:?1
-
-
-
- A list of supported keywords for Solr is shown below.
-
-
-
-
- Using @Query Annotation
-
- Using named queries (
-
- ) to declare queries for entities is a valid
- approach and works fine
- for a small number of queries. As the
- queries themselves are tied to
- the Java method that executes them,
- you actually can bind them
- directly using the Spring Data Solr
- @Query
- annotation.
-
-
-
- Declare query at the method using the
- @Query
- annotation.
-
-
- public interface ProductRepository extends SolrRepository<Product, String> {
- @Query("inStock:?0")
- List<Product> findByAvailable(Boolean available);
-}
-
-
-
- Using NamedQueries
-
- Named queries can be kept in a properties file and wired to the
- accroding method. Please mind the naming convention described in
-
- or use
- @Query
- .
-
-
-
- Declare named query in properites file
-
- Product.findByNamedQuery=popularity:?0
-Product.findByName=name:?0
- public interface ProductRepository extends SolrCrudRepository<Product, String> {
-
- List<Product> findByNamedQuery(Integer popularity);
-
- @Query(name = "Product.findByName")
- List<Product> findByAnnotatedNamedQuery(String name);
-
-}
-
-
-
-
\ No newline at end of file
diff --git a/src/docbkx/reference/repositories.xml b/src/docbkx/reference/repositories.xml
new file mode 100644
index 000000000..e9bd00853
--- /dev/null
+++ b/src/docbkx/reference/repositories.xml
@@ -0,0 +1,1111 @@
+
+
+
+ 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 not 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 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.
+
+
+
+
+ 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.
+
+
+ CrudRepository interface
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ public interface CrudRepository<T, ID extends Serializable>
+ extends Repository<T, ID> {
+
+ T save(T entity);
+
+ T findOne(ID primaryKey);
+
+ Iterable<T> findAll();
+
+ 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 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 this
+ interface.
+
+ On top of the CrudRepository there is
+ a PagingAndSortingRepository abstraction
+ that adds additional methods to ease paginated access to entities:
+
+
+ PagingAndSortingRepository
+
+ public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
+
+ Iterable<T> findAll(Sort sort);
+
+ Page<T> findAll(Pageable pageable);
+ }
+
+
+ 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
+ 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:
+
+
+
+ Declare an interface extending
+ Repository or one of its sub-interfaces
+ and type it to the domain class it shall handle.
+
+ public interface PersonRepository extends Repository<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>
+
+
+ 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.
+
+
+
+
+ Get the repository instance injected and use it.
+
+ public class SomeClient {
+
+ @Autowired
+ private PersonRepository 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 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. 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
+ Repository.
+
+
+ Fine tuning repository definition
+
+ Usually you will have your repository interface 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
+ want to expose from CrudRepository into
+ your domain repository.
+
+
+ Selectively exposing CRUD methods
+
+ interface MyBaseRepository<T, ID extends Serializable> extends Repository<T, ID> {
+ T findOne(ID id);
+ T save(T entity);
+ }
+
+ interface UserRepository extends MyBaseRepository<User, Long> {
+
+ User findByEmailAddress(EmailAddress emailAddress);
+ }
+
+
+ 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
+ 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.
+
+
+
+
+ Defining query methods
+
+
+ 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:
+
+
+ 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 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.
+
+
+
+ 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.
+
+
+
+
+ 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 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 Repository<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 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.
+
+
+ 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
+
+ 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).
+
+ 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:
+
+ 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.
+
+
+ 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.
+
+
+ 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
+ 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 its sub packages 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.
+
+
+ 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 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 interfaces ending in
+ SomeRepository from being
+ instantiated.
+
+
+
+
+
+ JavaConfig
+
+ 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.
+ JavaConfig in the Spring reference documentation -
+
+
+ A sample configuration to enable Spring Data repositories would
+ look something like this.
+
+
+ Sample annotation based repository configuration
+
+ @Configuration
+ @EnableJpaRepositories("com.acme.repositories")
+ class ApplicationConfiguration {
+
+ @Bean
+ public EntityManagerFactory entityManagerFactory() {
+ // …
+ }
+ }
+
+
+ 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.
+
+
+
+ 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:
+
+
+ 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 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.
+
+
+ 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 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 CrudRepository<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" />
+
+ <repositories base-package="com.acme.repository" repository-impl-postfix="FooBar" />
+
+
+ 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 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.
+
+
+ Manual wiring of custom implementations (I)
+
+ <repositories base-package="com.acme.repository" />
+
+ <beans:bean id="userRepositoryImpl" class="…">
+ <!-- further configuration -->
+ </beans: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 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.
+
+
+ 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.
+
+
+
+ Custom repository base class
+
+
+ public class MyRepositoryImpl<T, ID extends Serializable>
+ extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {
+
+ private EntityManager entityManager;
+
+ // There are two constructors to choose from, either can be used.
+ public MyRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
+ super(domainClass, entityManager);
+
+ // This is the recommended method for accessing inherited class dependencies.
+ this.entityManager = entityManager;
+ }
+
+ public void sharedCustomMethod(ID id) {
+ // 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.
+
+
+ Custom repository factory bean
+
+
+ public class MyRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable>
+ extends JpaRepositoryFactoryBean<R, T, I> {
+
+ protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
+
+ return new MyRepositoryFactory(entityManager);
+ }
+
+ private static class MyRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
+
+ private EntityManager entityManager;
+
+ public MyRepositoryFactory(EntityManager entityManager) {
+ super(entityManager);
+
+ this.entityManager = entityManager;
+ }
+
+ protected Object getTargetRepository(RepositoryMetadata metadata) {
+
+ return new MyRepositoryImpl<T, I>((Class<T>) metadata.getDomainClass(), entityManager);
+ }
+
+ protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
+
+ // The RepositoryMetadata can be safely ignored, it is used by the JpaRepositoryFactory
+ //to check for QueryDslJpaRepository's which is out of scope.
+ return MyRepository.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" />
+
+
+
+
+
+ Extensions
+
+ This chapter 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:
+
+ @Controller
+ @RequestMapping("/users")
+ public class UserController {
+
+ private final UserRepository userRepository;
+
+ public UserController(UserRepository userRepository) {
+ userRepository = userRepository;
+ }
+
+ @RequestMapping("/{id}")
+ public String showUserForm(@PathVariable("id") Long id, Model model) {
+
+ // Do null check for id
+ User user = userRepository.findOne(id);
+ // Do null check for user
+ // Populate model
+ return "user";
+ }
+ }
+
+ 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.
+
+
+ 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
+ custom PropertyEditor for the managed
+ domain class
+
+ <bean class="….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
+ <property name="webBindingInitializer">
+ <bean class="….web.bind.support.ConfigurableWebBindingInitializer">
+ <property name="propertyEditorRegistrars">
+ <bean class="org.springframework.data.repository.support.DomainClassPropertyEditorRegistrar" />
+ </property>
+ </bean>
+ </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.
+
+ @Controller
+ @RequestMapping("/users")
+ public class UserController {
+
+ @RequestMapping("/{id}")
+ public String showUserForm(@PathVariable("id") User user, Model model) {
+
+ // Do null check for user
+ // Populate model
+ return "userForm";
+ }
+ }
+
+
+
+ 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 register
+ the converter you have to declare
+ ConversionServiceFactoryBean, register the
+ converter and tell the Spring MVC namespace to use the configured
+ conversion service:
+
+ <mvc:annotation-driven conversion-service="conversionService" />
+
+ <bean id="conversionService" class="….context.support.ConversionServiceFactoryBean">
+ <property name="converters">
+ <list>
+ <bean class="org.springframework.data.repository.support.DomainClassConverter">
+ <constructor-arg ref="conversionService" />
+ </bean>
+ </list>
+ </property>
+ </bean>
+
+
+
+
+ Web pagination
+
+ @Controller
+ @RequestMapping("/users")
+ public class UserController {
+
+ // DI code omitted
+
+ @RequestMapping
+ public String showUsers(Model model, HttpServletRequest request) {
+
+ int page = Integer.parseInt(request.getParameter("page"));
+ int pageSize = Integer.parseInt(request.getParameter("pageSize"));
+ model.addAttribute("users", userService.getUsers(pageable));
+ return "users";
+ }
+ }
+
+ 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.
+
+ <bean class="….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
+ <property name="customArgumentResolvers">
+ <list>
+ <bean class="org.springframework.data.web.PageableArgumentResolver" />
+ </list>
+ </property>
+ </bean>
+
+ This configuration allows you to simplify controllers down to
+ something like this:
+
+ @Controller
+ @RequestMapping("/users")
+ public class UserController {
+
+ @RequestMapping
+ public String showUsers(Model model, Pageable pageable) {
+
+ model.addAttribute("users", userDao.readAll(pageable));
+ return "users";
+ }
+ }
+
+ The PageableArgumentResolver will
+ automatically resolve request parameters to build a
+ PageRequest instance. By default it will expect
+ the following structure for the request parameters:
+
+
+ Request parameters evaluated by
+ PageableArgumentResolver
+
+
+
+
+
+
+
+
+ page
+
+ The page you want to retrieve
+
+
+
+ page.size
+
+ The size of the page you want to retrieve
+
+
+
+ page.sort
+
+ The property that should be sorted by
+
+
+
+ page.sort.dir
+
+ The direction that should be used for sorting
+
+
+
+
+
+ In case you need multiple Pageables
+ to be resolved from the request (for multiple tables e.g.) you can use
+ Spring's @Qualifier annotation to
+ distinguish one from another. The request parameters then have to be
+ prefixed with ${qualifier}_. So a method signature like
+ this:
+
+ public String showUsers(Model model,
+ @Qualifier("foo") Pageable first,
+ @Qualifier("bar") Pageable second) { … }
+
+
+ you'd have to populate foo_page and
+ bar_page and the according subproperties.
+
+
+ Defaulting
+
+ The 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
+ 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
+ @PageableDefaults and specify page and
+ page size as annotation attributes:
+
+ public String showUsers(Model model,
+ @PageableDefaults(pageNumber = 0, value = 30) Pageable pageable) { … }
+
+
+
+
+
+ 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.
+
+ Assume you have a file data.json with the
+ following content:
+
+
+ Data defined in JSON
+
+ [ { "_class" : "com.acme.Person",
+ "firstname" : "Dave",
+ "lastname" : "Matthews" },
+ { "_class" : "com.acme.Person",
+ "firstname" : "Carter",
+ "lastname" : "Beauford" } ]
+
+
+ You can easily populate you 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:
+
+
+ Declaring a Jackson repository populator
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:repository="http://www.springframework.org/schema/data/repository"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/data/repository
+ http://www.springframework.org/schema/data/repository/spring-repository.xsd">
+
+ <repository:jackson-populator location="classpath:data.json" />
+
+ </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.
+
+ To rather use XML to define the repositories shall be populated
+ with you can use the unmarshaller-populator you hand one of the
+ marshaller options Spring OXM provides you with.
+
+
+ Declaring an unmarshalling repository populator (using
+ JAXB)
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:repository="http://www.springframework.org/schema/data/repository"
+ xmlns:oxm="http://www.springframework.org/schema/oxm"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/data/repository
+ http://www.springframework.org/schema/data/repository/spring-repository.xsd
+ http://www.springframework.org/schema/oxm
+ http://www.springframework.org/schema/oxm/spring-oxm.xsd">
+
+ <repository:unmarshaller-populator location="classpath:data.json" unmarshaller-ref="unmarshaller" />
+
+ <oxm:jaxb2-marshaller contextPath="com.acme" />
+
+ </beans>
+
+
+
+
\ No newline at end of file
diff --git a/src/main/assembly/distribution.xml b/src/main/assembly/distribution.xml
new file mode 100644
index 000000000..e8450e0cd
--- /dev/null
+++ b/src/main/assembly/distribution.xml
@@ -0,0 +1,52 @@
+
+
+
+ distribution
+
+ zip
+
+ true
+
+
+
+ src/main/resources
+
+ license.txt
+ notice.txt
+ changelog.txt
+
+
+ dos
+
+
+
+ target/site/reference
+ docs/reference
+
+
+
+ target/site/apidocs
+ docs/javadoc
+
+
+
+
+ target/${dist.finalName}.jar
+ dist
+ 0644
+
+
+ target/${dist.finalName}-sources.jar
+ sources
+ 0644
+
+
+
\ No newline at end of file
diff --git a/src/main/assembly/jar-with-dependencies.descriptor.xml b/src/main/assembly/jar-with-dependencies.descriptor.xml
new file mode 100644
index 000000000..b34b174fe
--- /dev/null
+++ b/src/main/assembly/jar-with-dependencies.descriptor.xml
@@ -0,0 +1,18 @@
+
+ all
+
+ jar
+
+ false
+
+
+ /
+ true
+ true
+ runtime
+ true
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/notice.txt b/src/main/resources/notice.txt
index 18aca5bcb..efbc1d75f 100644
--- a/src/main/resources/notice.txt
+++ b/src/main/resources/notice.txt
@@ -1,5 +1,4 @@
-Spring Data Solr 1.0
-Copyright (c) [2012] SpringSource, a division of VMware, Inc.
+Spring Data Elasticsearch
This product is licensed to you under the Apache License, Version 2.0 (the "License").
You may not use this product except in compliance with the License.
diff --git a/src/test/java/org/springframework/data/elasticsearch/core/query/CriteriaQueryTest.java b/src/test/java/org/springframework/data/elasticsearch/core/query/CriteriaQueryTest.java
index 18562e806..bfe480907 100644
--- a/src/test/java/org/springframework/data/elasticsearch/core/query/CriteriaQueryTest.java
+++ b/src/test/java/org/springframework/data/elasticsearch/core/query/CriteriaQueryTest.java
@@ -23,7 +23,6 @@ import static org.junit.Assert.assertTrue;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
-@Ignore
public class CriteriaQueryTest {
@Resource
@@ -476,13 +475,13 @@ public class CriteriaQueryTest {
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("rate").between(350,null));
//when
- SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery, SampleEntity.class);
+ Page page = elasticsearchTemplate.queryForPage(criteriaQuery, SampleEntity.class);
//then
- assertThat(sampleEntity,is(notNullValue()));
+ assertThat(page,is(notNullValue()));
+ assertThat(page.getTotalElements(),is(greaterThanOrEqualTo(1L)));
}
@Test
- @Ignore
public void testBetweenWithoutLowerBound() {
//given
List indexQueries = new ArrayList();
@@ -513,13 +512,13 @@ public class CriteriaQueryTest {
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("rate").between(null,550));
//when
- SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery, SampleEntity.class);
+ Page page = elasticsearchTemplate.queryForPage(criteriaQuery, SampleEntity.class);
//then
- assertThat(sampleEntity,is(notNullValue()));
+ assertThat(page,is(notNullValue()));
+ assertThat(page.getTotalElements(),is(greaterThanOrEqualTo(1L)));
}
@Test
- @Ignore
public void testLessThanEqauls() {
//given
List indexQueries = new ArrayList();
@@ -550,13 +549,13 @@ public class CriteriaQueryTest {
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("rate").lessThanEqual(750));
//when
- SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery, SampleEntity.class);
+ Page page = elasticsearchTemplate.queryForPage(criteriaQuery, SampleEntity.class);
//then
- assertThat(sampleEntity,is(notNullValue()));
+ assertThat(page,is(notNullValue()));
+ assertThat(page.getTotalElements(),is(greaterThanOrEqualTo(1L)));
}
@Test
- @Ignore
public void testGreaterThanEqauls() {
//given
List indexQueries = new ArrayList();
@@ -587,9 +586,10 @@ public class CriteriaQueryTest {
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("rate").greaterThanEqual(950));
//when
- SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery, SampleEntity.class);
+ Page page = elasticsearchTemplate.queryForPage(criteriaQuery, SampleEntity.class);
//then
- assertThat(sampleEntity,is(notNullValue()));
+ assertThat(page,is(notNullValue()));
+ assertThat(page.getTotalElements(),is(greaterThanOrEqualTo(1L)));
}
@Test
diff --git a/src/test/java/org/springframework/data/elasticsearch/repositories/CustomMethodRepositoryTest.java b/src/test/java/org/springframework/data/elasticsearch/repositories/CustomMethodRepositoryTest.java
index 46073da4a..790228a13 100644
--- a/src/test/java/org/springframework/data/elasticsearch/repositories/CustomMethodRepositoryTest.java
+++ b/src/test/java/org/springframework/data/elasticsearch/repositories/CustomMethodRepositoryTest.java
@@ -1,20 +1,23 @@
package org.springframework.data.elasticsearch.repositories;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.SampleEntity;
+import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
+import org.springframework.data.elasticsearch.core.query.DeleteQuery;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import static org.apache.commons.lang.RandomStringUtils.randomNumeric;
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
+import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
+import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
@@ -24,6 +27,18 @@ public class CustomMethodRepositoryTest {
@Resource
private SampleCustomMethodRepository repository;
+ @Autowired
+ private ElasticsearchTemplate elasticsearchTemplate;
+
+ @Before
+ public void before(){
+ elasticsearchTemplate.createIndex(SampleEntity.class);
+ DeleteQuery deleteQuery = new DeleteQuery();
+ deleteQuery.setElasticsearchQuery(matchAllQuery());
+ elasticsearchTemplate.delete(deleteQuery,SampleEntity.class);
+ elasticsearchTemplate.refresh(SampleEntity.class, true);
+ }
+
@Test
public void shouldExecuteCustomMethod(){
//given
@@ -40,6 +55,22 @@ public class CustomMethodRepositoryTest {
assertThat(page.getTotalElements(), is(greaterThanOrEqualTo(1L)));
}
+ @Test
+ public void shouldExecuteCustomMethodForNext(){
+ //given
+ String documentId = randomNumeric(5);
+ SampleEntity sampleEntity = new SampleEntity();
+ sampleEntity.setId(documentId);
+ sampleEntity.setType("some");
+ sampleEntity.setMessage("some message");
+ repository.save(sampleEntity);
+ //when
+ Page page = repository.findByTypeNot("test", new PageRequest(1, 10));
+ //then
+ assertThat(page, is(notNullValue()));
+ assertThat(page.getTotalElements(), is(greaterThanOrEqualTo(1L)));
+ }
+
@Test
public void shouldExecuteCustomMethodWithQuery(){
//given
@@ -56,4 +87,31 @@ public class CustomMethodRepositoryTest {
assertThat(page.getTotalElements(), is(greaterThanOrEqualTo(1L)));
}
+
+ @Test
+ public void shouldExecuteCustomMethodWithLessThan(){
+ //given
+ String documentId = randomNumeric(5);
+ SampleEntity sampleEntity = new SampleEntity();
+ sampleEntity.setId(documentId);
+ sampleEntity.setType("test");
+ sampleEntity.setRate(10);
+ sampleEntity.setMessage("some message");
+ repository.save(sampleEntity);
+
+ String documentId2 = randomNumeric(5);
+ SampleEntity sampleEntity2 = new SampleEntity();
+ sampleEntity2.setId(documentId2);
+ sampleEntity2.setType("test");
+ sampleEntity2.setRate(20);
+ sampleEntity2.setMessage("some message");
+ repository.save(sampleEntity2);
+
+ //when
+ Page page = repository.findByRateLessThan(10, new PageRequest(1, 10));
+ //then
+ assertThat(page, is(notNullValue()));
+ assertThat(page.getTotalElements(), is(equalTo(1L)));
+ }
+
}
diff --git a/src/test/java/org/springframework/data/elasticsearch/repositories/SampleCustomMethodRepository.java b/src/test/java/org/springframework/data/elasticsearch/repositories/SampleCustomMethodRepository.java
index f384e2dfd..ba1ddd085 100644
--- a/src/test/java/org/springframework/data/elasticsearch/repositories/SampleCustomMethodRepository.java
+++ b/src/test/java/org/springframework/data/elasticsearch/repositories/SampleCustomMethodRepository.java
@@ -11,7 +11,13 @@ public interface SampleCustomMethodRepository extends ElasticsearchRepository findByType(String type, Pageable pageable);
+ Page findByTypeNot(String type, Pageable pageable);
+
@Query("{\"bool\" : {\"must\" : {\"field\" : {\"message\" : \"?0\"}}}}")
Page findByMessage(String message, Pageable pageable);
+ Page findByRateLessThan(int rate, Pageable pageable);
+
+ Page findByRateBefore(int rate, Pageable pageable);
+
}