We now allow for registering RepositoryMethodInvocationListeners to notify listeners upon repository method invocations (query methods and repository fragments). Listeners are notified upon method completion reporting the repository interface, the invoked methods, duration, outcome and arguments.
Original Pull Request: #455
Revert bean name change so all nested repository interface components (repository bean, fragment bean, legacy custom implementation bean) remain prefixed with their enclosing type name.
Adopt tests. Add test for RepositoryBeanDefinitionRegistrar. Extend documentation.
Original pull request: #460.
Problem: while repository and fragment interfaces are discovered
correctly (provided that considerNestedRepositories=true), their
implementations are not found/registered despite proper class naming.
Cause: DefaultImplementationLookupConfiguration works in such way that
for nested interface (i.e. one whose class name includes name of the
enclosing class) expected implementation class name is built including
that enclosing class name. In the same time actual implementation class
names are always "localized" (i.e. stripped from enclosing class name,
if any) before matching. This makes matching implementation classes
against nested interface impossible.
Solution: when building expected implementation class name, use "local"
interface class name, so that it can match any implementation class that
follows naming convention "SimpleInterfaceName" + "ImplemenetationPostfix".
Original pull request: #460.
We now use a dedicated GetOptions instance for the lookup of the parent path in case SetOptions is defined to skip nulls so that the lookup does not fail if the parent path contains a null value.
Use a more lenient approach, that allows metadata creation, when looking up persistent entities. This allows eg. a configured AuditingHandler to kick in without having to register an initial entity set in first place.
Original pull request: #462.
kotlin.Unit is now considered a simple type to avoid PersistentEntity creation.
ReflectionUtils.isVoid(…) now encapsulates the check so that calling code doesn't need to check if Kotlin is on the class path.
We now support reactive EvaluationContext retrieval in conjunction with ReactiveEvaluationContextExtensions. Reactive SpEL Context extensions may access Reactor's Context and provide contextual details during SpEL evaluation.
Original Pull Request: #454
We now invoke BeanNameGenerator directly without additional indirections. Previously, SpringDataAnnotationBeanNameGenerator was calling BeanNameGenerator using null for BeanDefinitionRegistry which caused downstream null dereference.
We now provide a reactive variant for auditing with ReactiveAuditingHandler and ReactiveIsNewAwareAuditingHandler.
Extracted common auditing functionality into AuditingHandlerSupport which serves as base class for AuditingHandler and ReactiveAuditingHandler.
Original Pull Request: #458
We now reuse the new bean in InstantiationAwarePropertyAccessor when setting properties. Previously, we used the initial bean state as the bean was held by a delegate PersistentPropertyAccessor which caused only the last set property to be visible.
We now provide callback hook operators that allow attaching of a Runnable and Consumer<Throwable> to a reactive wrapper type for participating in terminal signals.
Fix `DefaultRepositoryMetadataUnitTests` to import the `java.util`
version of `Optional` rather than the `com.google` variant.
Original pull request: #448.
Check for deferred types in ReactiveWrappers so that ReactiveWrapperConverters remains untouched as wrapper conversion from a reactive type into CompletableFuture is still possible from a ReactiveWrapperConverters perspective.
Original pull request: #450.
CompletableFuture use is permitted in imperative repositories so we should not use CompletableFuture as indicator to switch a repository implementation to a reactive one.
Original pull request: #450.
We now avoid identifier conversion in ReflectionrepositoryConverter if not necessary. Reestablish a couple of unit tests for DomainClassConverter that were disabled by accident.
Made the reference to RepositoryInformation non-nullable from the RepositoryAnnotationTransactionAttributeSource (previously RepositoryInformationPreferring…). Adapted test cases accordingly.
We now no longer duplicate Spring Framework code as AbstractFallbackTransactionAttributeSource exposes computeTransactionAttribute which we can use to override to determine TransactionAttribute from the repository interface.
Renamed CustomAnnotationTransactionAttributeSource to RepositoryInformationPreferringAnnotationTransactionAttributeSource to reflect the nature of our customization.
We now eagerly register DomainClassConverter as converter with the ConversionService in the web setup. We also refrain from explicitly registering the traget converters with the ConversionService as that might trigger a ConcurrentModificationException if called during an iteration over the converters in the first place. As DomainClassConverter registers itself for all ConvertiblePairs and delegates to the individual converters anyway.
We now expose RepositoryMetadata.getReturnType(…) to obtain the declared method return type. While pure Java code can rely on Method.getReturnType(), suspended Kotlin methods (Coroutines) require additional lookups. This is because the Kotlin compiler messes around with the return type in the bytecode. It changes the return type to java.lang.Object while synthesizing an additional method argument:
interface MyCoroutineRepository : Repository<Person, String> {
suspend fun suspendedQueryMethod(): Flow<Person>
}
compiles to
interface MyCoroutineRepository extends Repository<Person, String> {
Object suspendedQueryMethod(Continuation<Flow<Person>> arg0);
}
Therefore, the triviality of obtaining a return type becomes an inspection of the actual method arguments.
Related ticket: https://jira.spring.io/browse/DATAMONGO-2562
DomainClassConverter now delays the initialization of the Repositories instances used to avoid the premature initialization of repository instances as that can cause deadlocks if the infrastructure backing the repositories is initialized on a separate thread.
Refactored nested converter classes to allow them to be static ones.
Related issues: spring-projects/spring-boot#16230, spring-projects/spring-framework#25131.
Original pull request: #445.
Use mutated object as guard for synchronization. Copy discovered callbacks to cached callbacks.
Reduce concurrency in unit test to reduce test load. Guard synchronization with timeouts.
Original pull request: #446.
Encapsulate field and introduce getter for ConversionService. Add missing Override annotation. Add author tags. Minor cleanups.
Original pull request: #432.
We now use the correct quotation map that is based on the rewritten SpEL query to detect whether an expression was quoted.
Previously, we used the quotation map from the original query.
After augmenting the query with synthetic parameters, the quotation offset no longer matched the query that ß∑was under inspection and calls to SpelExtractor.isQuoted(…) could report an improper result.
Original pull request: #434.
We now pick up case-insensitive sorting flags by parsing it up from a sort query string argument.
To enable ignore case for one or more properties, we expect "ignorecase" as last element in a sort spec. Sort order and case-sensitivity options are parsed case-insensitive for a greater flexibility:
http://localhost/?sort=firstname,IgnoreCase or http://localhost/?sort=firstname,ASC,ignorecase
Original pull request: #172.
Replace list creation with constant. Replace ConverterConfiguration.skipFor list with Predicate for flexible conditions. Fix typo. Simplify conditionals.
Original pull request: #421.
CustomConversions now registers all given user defined converters and selects only those converters from the StoreConversions that convert to or from a store supported simple type.
By doing so we make sure to only register supported converters which removes warning messages from the log and reduces the number of converters within the ConversionService.
Original pull request: #421.
We now expose a dedicated PersistentPropertyPathAccessor and optionally take options for both the read and write access to properties. On read, clients can define to eagerly receive null in case one of the path segments is null. By default, we reject those as it indicates that there might be an issue with the backing object if the client assumes it can look up the more deeply nested path to receive a result.
On write access clients can define to either reject, skip or log intermediate null segments where skip means, that the setting is just silently aborted. Clients can also control how to deal with collection and map intermediates. By default we now propagate the attempt to set a value to all collection or map items respectively. This could be potentially extended to provide a filter receiving both the property and property value to selectively propagate those calls in the future.
The separation of these APIs (PersistentPropertyAccessor and PersistentPropertyPathAccessor) is introduced as the latter can be implemented on top of the former and the former potentially being dynamically generated. The logic of the latter can then be clearly separated from the actual individual property lookup. ConvertingPropertyAccessor is now a PersistentPropertyPathAccessor, too, and overrides SimplePersistentPropertyPathAccessor.getTypedProperty(…) to plug in conversion logic. This allows custom collection types being used if the ConversionService backing the accessor can convert from and to Collection or Map respectively.
Deprecated all PersistentPropertyPath-related methods on PersistentPropertyAccessor for removal in 2.3.
MappingAuditableBeanWrapperFactory now uses these new settings to skip both null values as well as collection and map values when setting auditing metadata.
Related tickets: DATACMNS-1438, DATACMNS-1461, DATACMNS-1609.