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.
Switch property parameter cache from HashMap and external locks to ConcurrentHashMap to improve multi-threaded locking behavior during isConstructorParameter(…) initialization.
Original pull request: #437.
Encapsulate field and introduce getter for ConversionService. Add missing Override annotation. Add author tags. Minor cleanups.
Original pull request: #432.
We now avoid a type reference to XmlBeamHttpMessageConverter in a field within SpringDataWebConfiguration to avoid a type reference to a potentially unresolvable type. This seems to have caused issues on certain JDK 14 builds [0].
[0] https://github.com/spring-projects/spring-framework/issues/25050
Reorder constructor filtering with the goal to delay/avoid potentially expensive PersistenceConstructor creation with parameter lookup as much as possible.
The lookup is (in a default setup) only done once per domain type, but depending on the number of entities to inspect the change can help save some cycles for larger domains.
Before:
Benchmark Mode Cnt Score Error Units
EntityMetadataBenchmark.alwaysNew thrpt 10 224318,163 ± 42542,453 ops/s
After:
Benchmark Mode Cnt Score Error Units
EtityMetadataBenchmark.alwaysNew thrpt 10 420053,505 ± 9288,093 ops/s
public class DomainType {
private String id;
private @Id String theId;
private String firstname, lastname;
private Integer age;
public DomainType(String id, String theId, String firstname, String lastname, Integer age) {
this.id = id;
this.theId = theId;
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
}
@PersistenceConstructor
public DomainType(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
}
Original pull request: #440.
Delete by Flow is now suspended as the delete method completion is driven by the given Flow. To allow for synchronization, this method is suspended and awaits completion.
We now detect whether callbacks are present before we create result lists instead of always allocating a Collection. CallbackRetriever now also returns a cached variant of its list of callbacks instead of always allocating a new ArrayList.
Kotlin coroutine methods are compiled returning Object so the original return type gets lost. We resolve the return type from the Continuation parameter that synthetized as last parameter in a coroutine method declaration.
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.