Skip to content

Commit 638e956

Browse files
committed
DATACMNS-1444 - Added documentation on Streamable and collection return types.
Includes documentation of Vavr return types.
1 parent f2967a9 commit 638e956

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

src/main/asciidoc/repositories.adoc

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,88 @@ In the prior example, you defined a common base interface for all your domain re
225225

226226
NOTE: The intermediate repository interface is annotated with `@NoRepositoryBean`. Make sure you add that annotation to all repository interfaces for which Spring Data should not create instances at runtime.
227227

228+
[[repositories.collections-and-iterables]]
229+
=== Repository Methods Returning Collections or Iterables
230+
Query methods that return multiple results can use standard Java `Iterable`, `List`, `Set`.
231+
Beyond that we support returning Spring Data's `Streamable`, a custom extension of `Iterable`, as well as collection types provided by http://www.vavr.io/[Vavr].
232+
233+
[[repositories.collections-and-iterables.streamable]]
234+
==== Using Streamable as Query Method Return Type
235+
`Streamable` can be used as alternative to `Iterable` or any collection type.
236+
It provides convenience methods to access a non-parallel `Stream` (missing from `Iterable`), the ability to directly `….filter(…)` and `….map(…)` over the elements and concatenate the `Streamable` to others:
237+
238+
.Using Streamable to combine query method results
239+
====
240+
[source, java]
241+
----
242+
interface PersonRepository extends Repository<Person, Long> {
243+
Streamable<Person> findByFirstnameContaining(String firstname);
244+
Streamable<Person> findByLastnameContaining(String lastname);
245+
}
246+
247+
Streamable<Person> result = repository.findByFirstnameContaining("av")
248+
.and(repository.findByLastnameContaining("ea"));
249+
----
250+
====
251+
252+
[[repositories.collections-and-iterables.streamable-wrapper]]
253+
==== Returning Custom Streamable Wrapper Types
254+
255+
Providing dedicated wrapper types for collections is a commonly used pattern to provide API on a query execution result that returns multiple elements.
256+
Usually these types are used by invoking a repository method returning a collection-like type and creating an instance of the wrapper type manually.
257+
That additional step can be avoided as Spring Data allows to use these wrapper types as query method return types if they meet the following criterias:
258+
259+
. The type implements `Streamable`.
260+
. The type exposes either a constructor or a static factory method named `of(…)` or `valueOf(…)` taking `Streamable` as argument.
261+
262+
A sample use case looks as follows:
263+
264+
====
265+
[source, java]
266+
----
267+
class Product { <1>
268+
MonetaryAmount getPrice() { … }
269+
}
270+
271+
@RequiredArgConstructor(staticName = "of")
272+
class Products implements Streamable<Product> { <2>
273+
274+
private Streamable<Product> streamable;
275+
276+
public MonetaryAmount getTotal() { <3>
277+
return streamable.stream() //
278+
.map(Priced::getPrice)
279+
.reduce(Money.of(0), MonetaryAmount::add);
280+
}
281+
}
282+
283+
interface ProductRepository implements Repository<Product, Long> {
284+
Products findAllByDescriptionContaining(String text); <4>
285+
}
286+
----
287+
<1> A `Product` entity that exposes API to access the product's price.
288+
<2> A wrapper type for a `Streamable<Product>` that can be constructed via `Products.of(…)` (factory method created via the Lombok annotation).
289+
<3> The wrapper type exposes additional API calculating new values on the `Streamable<Product>`.
290+
<4> That wrapper type can be used as query method return type directly. No need to return `Stremable<Product>` and manually wrap it in the repository client.
291+
====
292+
293+
[[repositories.collections-and-iterables.vavr]]
294+
==== Support for Vavr Collections
295+
296+
http://www.vavr.io/[Vavr] is a library to embrace functional programming concepts in Java.
297+
It ships with a custom set of collection types that can be used as query method return types.
298+
299+
[options=header]
300+
|====
301+
|Vavr collection type|Used Vavr implementation type|Valid Java source types
302+
|`io.vavr.collection.Seq`|`io.vavr.collection.List`|`java.util.Iterable`
303+
|`io.vavr.collection.Set`|`io.vavr.collection.LinkedHashSet`|`java.util.Iterable`
304+
|`io.vavr.collection.Map`|`io.vavr.collection.LinkedHashMap`|`java.util.Map`
305+
|====
306+
307+
The types in the first column (or subtypes thereof) can be used as quer method return types and will get the types in the second column used as implementation type depending on the Java type of the actual query result (thrid column).
308+
Alternatively, `Traversable` (Vavr the `Iterable` equivalent) can be declared and we derive the implementation class from the actual return value, i.e. a `java.util.List` will be turned into a Vavr `List`/`Seq`, a `java.util.Set` becomes a Vavr `LinkedHashSet`/`Set` etc.
309+
228310
[[repositories.nullability]]
229311
=== Null Handling of Repository Methods
230312

src/main/asciidoc/repository-query-return-types-reference.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ NOTE: Geospatial types (such as `GeoResult`, `GeoResults`, and `GeoPage`) are av
2121
|`Optional<T>`|A Java 8 or Guava `Optional`. Expects the query method to return one result at most. If no result is found, `Optional.empty()` or `Optional.absent()` is returned. More than one result triggers an `IncorrectResultSizeDataAccessException`.
2222
|`Option<T>`|Either a Scala or Vavr `Option` type. Semantically the same behavior as Java 8's `Optional`, described earlier.
2323
|`Stream<T>`|A Java 8 `Stream`.
24+
|`Streamable<T>`|A convenience extension of `Iterable` that directy exposes methods to stream, map and filter results, concatenate them etc.
25+
|Types that implement `Streamable` and take a `Streamable` constructor or factory method argument|Types that expose a constructor or `….of(…)`/`….valueOf(…)` factory method taking a `Streamable` as argument. See <<repositories.collections-and-iterables.streamable-wrapper>> for details.
26+
|Vavr `Seq`, `List`, `Map`, `Set`|Vavr collection types. See <<repositories.collections-and-iterables.vavr>> for details.
2427
|`Future<T>`|A `Future`. Expects a method to be annotated with `@Async` and requires Spring's asynchronous method execution capability to be enabled.
2528
|`CompletableFuture<T>`|A Java 8 `CompletableFuture`. Expects a method to be annotated with `@Async` and requires Spring's asynchronous method execution capability to be enabled.
2629
|`ListenableFuture`|A `org.springframework.util.concurrent.ListenableFuture`. Expects a method to be annotated with `@Async` and requires Spring's asynchronous method execution capability to be enabled.

0 commit comments

Comments
 (0)