We now publish events for all methods named "save" on the repository. Fundamentally, that's in place to capture calls to CrudRepository.save(Iterable entities), too.
Some minor refactorings to the internal setup of EventPublishingMethodInterceptor. More JavaDoc.
Introduced @DomainEvents usable on a method of an aggregate root. The method will be invoked when the aggregate is passed to a repository to save and its returned value or values will be exposed via an ApplicationEventListener.
Also, the aggregate can expose a method annotated with @AfterDomainEventPublication which will be invoked once all events have been published.
We now try to look up a target class method based on concrete name and parameter type before falling back on the more expensive type matches. This also eliminates the possibility of invalid method matches as described in the ticket.
We now no longer attempt query creation for static methods declared on a repository interface. This allows static method usage inside of repository interfaces.
interface PersonRepository extends CrudRepository<Person, String> {
static String createId() {
// …
}
default Person findPerson() {
return findOne(createId());
}
}
The Descriptor class is nested in the ReactiveAdapter interface which in turn has a strong dependency to Project Reactor as it exposes some if its types as method return types. That means we can't refer to Spring's Descriptor without Project Reactor on the classpath.
Introduced a custom Descriptor that exposes the setup needs we have using a fluent API.
We now also only conditionally actually the ReactiveAdapterRegistry as eagerly instantiating it in RectiveWrapperConverter causes a strong dependency on Reactor.
Related tickets: DATACMNS-836, SPR-14902.
Reactive type conversion now happens fully inside of ReactiveWrapperConverters and does not require an external ConversionService. This change allows changes to reactive type conversion without changing the API since all details are encapsulated by ReactiveWrapperConverters.
Introduced ReactiveRepositoryFactorySupport so that validation for the presence of all required converters (e.g. RxJava 1) does not have to be repeated in individual stores.
RepositoryConfigurationExtensionSupport now exposes a ….useRepositoryConfiguration(RepositoryMetadata) so that extensions can opt in or out of an interface taking part in configuration more easily. Turned loadRepositoryInterface(…) private again as extensions should be able to just inspect the RepositoryMetadata now.
Some parameter rename in ReactiveWrapperConverters to avoid confusion.
RepositoryMetadata now exposes an ….isReactiveRepository() that's implemented by inspecting the backing repository interface for any reactive wrapper type appearing in method signatures. That allows us to move down the use of a ConversionService down to ReactiveRepositoryInformation.WrapperConversionMatch.
Made a couple of methods static that could be. Simplified some logic using streams. A bit better wording in assertions. Some formatting when using streams.
Move reactive wrapper conversion to ReactiveWrapperConverters to minimize touching points with reactive APIs. ReactiveWrapperConverters is used only from reactive repository components and does not initialize with blocking API use. This removes the need of having Project Reactor on the class path for non-reactive use.
- Rename RxJava...Repository to RxJava1...Repository
- Use Completable and Observable instead of Single for results without values/optional values
- Remove reactive paging for now as it does not really fit reactive data streaming
- Expose ReactiveWrappers.isAvailable(ReactiveLibrary) method to query library availability
We now expose reactive interfaces to facilitate reactive repository support in store-specific modules. Spring Data modules are free to implement their reactive support using either RxJava 1 or Project Reactor (Reactive Streams). We expose a set of base interfaces:
* `ReactiveCrudRepository`
* `ReactiveSortingRepository`
* `RxJava1CrudRepository`
* `RxJava1SortingRepository`
Reactive repositories provide a similar feature coverage to blocking repositories. Reactive paging support is limited to a `Mono<Page>`/`Single<Page>`. Data is fetched in a deferred way to provide a paging experience similar to blocking paging.
A store module can choose either Project Reactor or RxJava 1 to implement reactive repository support. Project Reactor and RxJava types are converted in both directions allowing repositories to be composed of Project Reactor and RxJava 1 query methods. Reactive wrapper type conversion handles wrapper type conversion at repository level. Query/implementation method selection uses multi-pass candidate selection to invoke the most appropriate method (exact arguments, convertible wrappers, assignable arguments).
We also provide ReactiveWrappers to expose metadata about reactive types and their value multiplicity.
PageableHandlerMethodArgumentResolver.isFallbackPageable() now correctly guards against the fallback Pageable being null, a situation that's explicitly deemed valid in setFallbackPageable(…).
This commit changes some ArrayList initializations to use an initial capacity and avoids the unnecessary fetch of the return type of a method in Parameter.isDynamicProjectionParameter().
Original pull request: #180.
The special case of an Iterable parameter doesn't have to be handled explicitly anymore so that we can simplify the type match check in DefaultRepositoryInformation.
Related ticket: DATACMNS-912.
Previously, ClassGeneratingPropertyAccessorFactory uses boxed types for primitive type setters. This threw NoSuchMethodExceptions and caused ExceptionInInitializerError as the generated class could not be initialized. We now use the appropriate argument type to look up setters.
Also, we now only generate accessor usage if the property is configured to use property access in the first place.
Original pull request: #178.
QueryExecutionResultHandler now explicitly handles null values for query methods returning Maps by returning an empty Map. This can be the case if a query is supposed to produce a Map (a single result) but doesn't actually yield any results at all.