diff --git a/readme.md b/readme.md index f8738fb08f..a1ce7fdafc 100644 --- a/readme.md +++ b/readme.md @@ -17,7 +17,7 @@ ### Prerequisites - Maven 3 -- Java 7 (the project produces Java 6 compatible bytecode but partially integrates with Java 7) +- Java 8 (the project produces Java 6 compatible bytecode but partially integrates with Java 8) ``` $ git clone https://github.com/spring-projects/spring-data-commons.git @@ -29,7 +29,7 @@ $ mvn clean install This README as well as the [reference documentation](http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/) are the best places to start learning about Spring Data Commons. -The main project [website](http://www.springsource.org/spring-data) contains links to basic project information such as source code, JavaDocs, Issue tracking, etc. +The main project [website](http://projects.spring.io/spring-data/) contains links to basic project information such as source code, JavaDocs, Issue tracking, etc. For more detailed questions, please refer to [spring-data on stackoverflow](http://stackoverflow.com/questions/tagged/spring-data). If you are new to Spring as well as to Spring Data, look for information about [Spring projects](https://spring.io/projects). @@ -37,7 +37,7 @@ For more detailed questions, please refer to [spring-data on stackoverflow](http Here are some ways for you to get involved in the community: -* Create [JIRA](https://jira.springsource.org/browse/DATACMNS) tickets for bugs and new features and comment and vote on the ones that you are interested in. +* Create [JIRA](https://jira.spring.io/browse/DATACMNS) tickets for bugs and new features and comment and vote on the ones that you are interested in. * Github is for social coding: if you want to write code, we encourage contributions through pull requests from [forks of this repository](http://help.github.com/forking/). If you want to contribute code this way, please reference a JIRA ticket as well covering the specific issue you are addressing. * Watch for upcoming articles on Spring by [subscribing](https://spring.io/blog.atom) to springframework.org diff --git a/src/main/asciidoc/dependencies.adoc b/src/main/asciidoc/dependencies.adoc index 2fd0a0f88b..86724e4404 100644 --- a/src/main/asciidoc/dependencies.adoc +++ b/src/main/asciidoc/dependencies.adoc @@ -16,7 +16,7 @@ Due to different inception dates of individual Spring Data modules, most of them import pom - + ---- ==== diff --git a/src/main/asciidoc/repositories.adoc b/src/main/asciidoc/repositories.adoc index 1de7988de1..127fab5ff0 100644 --- a/src/main/asciidoc/repositories.adoc +++ b/src/main/asciidoc/repositories.adoc @@ -1,3 +1,6 @@ +:spring-framework-docs: http://docs.spring.io/spring/docs/current/spring-framework-reference/html + + [[repositories]] = Working with Spring Data Repositories @@ -276,7 +279,7 @@ To resolve this ambiguity you can use `_` inside your method name to manually de List findByAddress_ZipCode(ZipCode zipCode); ---- -As we treat underscore as a reserved character we stongly advise to follow standard Java naming conventions (i.e. *not* using underscores in property names but camel case instead). +As we treat underscore as a reserved character we strongly advise to follow standard Java naming conventions (i.e. *not* using underscores in property names but camel case instead). [[repositories.special-parameters]] === Special parameter handling @@ -363,6 +366,28 @@ try (Stream stream = repository.findAllByCustomQueryAndStream()) { ==== NOTE: Not all Spring Data modules currently support `Stream` as a return type. +[[repositories.query-async]] +=== Async query results + +Repository queries can be executed asynchronously using link:{spring-framework-docs}#scheduling[Spring's asynchronous method execution capability]. This means the method will return immediately upon invocation and the actual query execution will occur in a task that has been submitted to a Spring TaskExecutor. + +==== +[source, java] +---- +@Async +Future findByFirstname(String firstname); <1> + +@Async +CompletableFuture findOneByFirstname(String firstname); <2> + +@Async +ListenableFuture findOneByLastname(String lastname); <3> +---- +<1> Use `java.util.concurrent.Future` as return type. +<2> Use a Java 8 `java.util.concurrent.CompletableFuture` as return type. +<3> Use a `org.springframework.util.concurrent.ListenableFuture` as return type. +==== + [[repositories.create-instances]] == Creating repository instances In this section you create instances and bean definitions for the repository interfaces defined. One way to do so is using the Spring namespace that is shipped with each Spring Data module that supports the repository mechanism although we generally recommend to use the Java-Config style configuration. @@ -764,6 +789,86 @@ Assume we have 30 Person instances in the database. You can now trigger a reques You see that the assembler produced the correct URI and also picks up the default configuration present to resolve the parameters into a `Pageable` for an upcoming request. This means, if you change that configuration, the links will automatically adhere to the change. By default the assembler points to the controller method it was invoked in but that can be customized by handing in a custom `Link` to be used as base to build the pagination links to overloads of the `PagedResourcesAssembler.toResource(…)` method. +[[core.web.type-safe]] +==== QueryDSL web support + +For those stores having http://www.querydsl.com/[QueryDSL] integration it is possible to derive queries from the attributes contained in a `Request` query string. + +This means that given the `User` object from previous samples a query string + +[source,text] +---- +?firstname=Dave&lastname=Matthews +---- + +can be resolved to + +[source,text] +---- +QUser.user.firstname.eq("Dave").and(QUser.user.lastname.eq("Matthews")) +---- + +using the `QuerydslPredicateArgumentResolver`. + +NOTE: The feature will be automatically enabled along `@EnableSpringDataWebSupport` when Querydsl is found on the classpath. + +Adding a `@QuerydslPredicate` to the method signature will provide a ready to use `Predicate` which can be executed via the `QueryDslPredicateExecutor`. + +TIP: Type information is typically resolved from the methods return type. Since those information does not necessarily match the domain type it might be a good idea to use the `root` attribute of `QuerydslPredicate`. + +==== +[source,java] +---- +@Controller +class UserController { + + @Autowired UserRepository repository; + + @RequestMapping(value = "/", method = RequestMethod.GET) + String index(Model model, @QuerydslPredicate(root = User.class) Predicate predicate, <1> + Pageable pageable, @RequestParam MultiValueMap parameters) { + + model.addAttribute("users", repository.findAll(predicate, pageable)); + + return "index"; + } +} +---- +<1> Resolve query string arguments to matching `Predicate` for `User`. +==== + +The default binding is as follows: + +* `Object` on simple properties as `eq`. +* `Object` on collection like properties as `contains`. +* `Collection` on simple properties as `in`. + +Those bindings can be customized via the `bindings` attribute of `@QuerydslPredicate` or by making use of Java 8 `default methods` adding the `QuerydslBinderCustomizer` to the repository interface. + +==== +[source,java] +---- +interface UserRepository extends CrudRepository, + QueryDslPredicateExecutor, <1> + QuerydslBinderCustomizer { <2> + + @Override + default public void customize(QuerydslBindings bindings, QUser user) { + + bindings.bind(user.username).first((path, value) -> path.contains(value)) <3> + bindings.bind(String.class) + .first((StringPath path, String value) -> path.containsIgnoreCase(value)); <4> + bindings.excluding(user.password); <5> + } +} +---- +<1> `QueryDslPredicateExecutor` provides access to specific finder methods for `Predicate`. +<2> `QuerydslBinderCustomizer` defined on the repository interface will be automatically picked up and shortcuts `@QuerydslPredicate(bindings=...)`. +<3> Define the binding for the `username` property to be a simple contains binding. +<4> Define the default binding for `String` properies to be a case insensitive contains match. +<5> Exclude the _password_ property from `Predicate` resolution. +==== + [[core.repository-populators]] === Repository populators 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. diff --git a/src/main/asciidoc/repository-query-return-types-reference.adoc b/src/main/asciidoc/repository-query-return-types-reference.adoc index e0b135f366..48ed372398 100644 --- a/src/main/asciidoc/repository-query-return-types-reference.adoc +++ b/src/main/asciidoc/repository-query-return-types-reference.adoc @@ -20,6 +20,9 @@ NOTE: Geospatial types like (`GeoResult`, `GeoResults`, `GeoPage`) are only avai |`List`|A `List`. |`Optional`|A Java 8 or Guava `Optional`. Expects the query method to return one result at most. In case no result is found `Optional.empty()`/`Optional.absent()` is returned. More than one result will trigger an `IncorrectResultSizeDataAccessException`. |`Stream`|A Java 8 `Stream`. +|`Future`|A `Future`. Expects method to be annotated with `@Async` and requires Spring's asynchronous method execution capability enabled. +|`CompletableFuture`|A Java 8 `CompletableFuture`. Expects method to be annotated with `@Async` and requires Spring's asynchronous method execution capability enabled. +|`ListenableFuture`|A `org.springframework.util.concurrent.ListenableFuture`. Expects method to be annotated with `@Async` and requires Spring's asynchronous method execution capability enabled. |`Slice`|A sized chunk of data with information whether there is more data available. Requires a `Pageable` method parameter. |`Page`|A `Slice` with additional information, e.g. the total number of results. Requires a `Pageable` method parameter. |`GeoResult`|A result entry with additional information, e.g. distance to a reference location.