Introduced RepositoryFactorySupport.getProjectionFactory(…) to create a ProjectionFactory to be used for repository instances created. The default implementation uses the SpelAwareProxyProjectionFactory.
The ProjectionInformation implementation is now a named class so it can be used for more specialized implementations.
Original pull request: #243.
Related issue: DATAJPA-1173.
Previously, a call to AbstractMappingContext.getPersistentEntity(PersistentProperty) would've added potentially leniently added the type of the given PersistentProperty, no matter whether it's actually considered to be an entity in the first place. We now defensively check for whether the given property is to be considered an entity (taking potentially registered converters into account) before the potentially entity-creating by-type lookup.
More fixes of imports. Removed obsolete generics in constructor expressions. Removed a couple of compiler warnings in test cases. Removed assumption for test case to only run on JDK 9.
Original pull request: #259.
Make sure to use concurrent collection implementations for properties holding mutable state. Especially the ones making use of computeIfAbsent(…).
Usage of ConcurrentReferenceHashMap allows us to move on without additional changes as it allows to store null values, whereas ConcurrentHashMap would require us to store explicit NullValue placeholders for such cases, potentially causing trouble in downstream store specific projects.
JMH Benchmarks done with the Spring Data MongoDB mapping layer showed a potential performance loss of up to 5%. However a comparison between ConcurrentReferenceHashMap and ConcurrentHashMap did not show any significant difference in performance.
Original pull request: #259.
AbstractMappingContext.hasPersistentEntityFor(…) now also properly consideres the empty Optional as non-presence as that is held to allow to distinguish between a type completely unkown to the context, or already known but not considered a persistent entity.
Related pull request: #258.
In AbstractPersistentProperty, we now resolve the potentially generic return and parameter types of getters and setters. To achieve that Property has now been made aware of the actual owning type.
We now determine initial values for primitive parameters in Kotlin constructors that are absent (null) and defaulted. We default all Java primitive types to their initial zero value to prevent possible NullPointerExceptions. Kotlin defaulting uses a bitmask to determine which parameter should be defaulted but still requires the appropriate type.
Previously, null values were attempted to cast/unbox and caused NullPointerException even though they had default values through Kotlin assigned.
Original pull request: #255.
Throw MappingInstantiationException from KotlinClassGeneratingEntityInstantiator if instantiation fails to align behavior with ClassGeneratingEntityInstantiator. Report Kotlin constructor instead of Java constructor if available.
Original pull request: #255.
We now insert assertions for primitive types before passing these to the actual constructor to prevent NullPointerExceptions. We also output the index/parameter name if the parameter was null.
Original pull request: #255.
We now resolve Kotlin interface properties to inspect these for nullability. Kotlin-reflect does not resolve interface property accessors yet so we need to handle this aspect ourselves.
Related ticket: https://youtrack.jetbrains.com/issue/KT-20768.
Original pull request: #254.
We now eagerly resolve a generics declaration chain, which we previously - erroneously - expected GenericTypeResolver to do for us. Simplified TypeVariableTypeInformation implementation. Renamed ParameterizedTypeUnitTests to ParameterizedTypeInformationUnitTests.
Remove existing section on Null-safety. Augment Null handling section with bits of the previous documentation, explicitly describe annotations expressing null-constraints, include full-qualified imports, mention kotlin-reflect dependency for Kotlin metadata introspection. Align callouts, add links, slightly improve wording, typos. Extend year range in copyright header.
Original pull request: #253.
Previously, the publication of the event that indicated a PersistentEntity having been added to it took place before the write lock over the entities had been released. We now keep the lock smaller and publish the addition event *after* the lock has been released.
On query execution conversion, we now check an unwrapped Optional's value for assignability to the target type before looking into advanced conversion options to avoid unnecessary code invocations that would eventually return the same instance anyway.
We now attempt MethodHandle lookup with deep reflection capabilities via MethodHandles.privateLookupIn(…) to properly resolve default interface methods on interfaces with package-protected visibility. This API is only available in Java 9 so we need to rely on reflection.
Original pull request: #251.
Align Javadoc to reflect the non-null contract for Predicate arguments.
Mention unpaged/unsorted factory methods for Pageable/Sort arguments.
Related ticket: DATACMNS-1114.
Kept in a separate commit, so that it's easy to add again by reverting this commit. Removed, as the new behavior is effectively what had been documented as intended behavior all the time.
Original pull request: #248.
We now use FragmentMetadata to control the way fragement interfaces and base packages to scan are calculated. Refactored RepositoryConfiguration.getImplementationBasePackages() to not take a parameter.
Original pull request: #248.
Custom repository implementation scan defaults to the repository interface package and its subpackages and no longer scans all configured base packages. Scan for fragment implementations defaults to the fragment interface package. Using the interface package for scanning aligns the behavior with the documentation.
This default can be changed with @Enable…Repositories annotations that support the limitImplementationBasePackages parameter to scan in repository base packages for custom implementations:
@EnableJpaRepositories(limitImplementationBasePackages = false)
@Configuration
class AppConfiguration {
// …
}
Declaring the implementation along with the interface in the same package is an established design pattern allowing to limit the scanning scope. A limited scope improves scanning performance as it can skip elements on the classpath, that do not provide that particular package.
Previously, we scanned for implementations using the configured base packages that were also used to discover repository interfaces. These base packages can be broader for applications that spread repository interfaces across multiple packages.
When trying to determine if a parameter is a dynamic projection parameter, i.e. the parameter of type Class that determines the projection to use, now the type parameter of that method parameter gets compared with the unwrapped return type. Therefore this works now not only for Maps and Collections but also for the various wrappers defined in QueryExecutionConverters.
Moved the method for unwrapping the return type from AbstractRepositoryMetadata to QueryExecutionConverters in order to make it available to every class needing it. This also puts it closer to the data it is working on.
Original pull request: #250.
We no longer cache argument arrays in our EntityInstantiators to prevent changes to shared mutable state caused by reentrant calls.
Previously, a re-entrant call requesting an argument array of the same size as a previous call in the call stack reused the same array instance. Changes to this shared mutable state by multiple invocations caused an invalid state rendering wrong parameters for object instantiation. Removing the caching and only reusing an empty array for zero-arg constructors is the only safe approach for now.
Re-instantiation of object allocations results in a higher GC pressure but guarantee side effect-free instantiation and should be on-par with previous versions performance profile.
Original pull request: #247.
We now only inspect regular Kotlin classes with inspection to adapt Kotlin-specific behavior. Multipart-, synthetic and unknown classes are not supported. In such cases we fall back to the JVM reflection mechanism.
Non-regular classes are typically synthetic stubs, lambdas and SAM conversion which do not represent typical domain objects but rather technical bridge code.
Original pull request: #245.
We now fall back to default preferred constructor discovery if a Kotlin class has no primary constructor and no preferred constructor is resolved. Previously, primary constructor resolution yielded no result (returned null) which caused the subsequent Java constructor lookup to fail.
Original pull request: #244.