Based on the new infrastructure created by DATACMNS-1275, MappingAuditingMetadata now keeps PersistentPropertyPaths to point to the properties reflecting individual auditing metadata items rather than just PersistentPropertyPaths. With that in place we can now find those items in embedded types of the subject entity based on the detection setup of the MappingContext managing metadata for the entity.
As that means that multiple paths to a metadata item property can be found, we now use the first path found (the shortest one) for the lookup of the modification date.
Related tickets: DATACMNS-1275.
MappingContext now exposes a method to detect all property paths pointing to properties matching a given predicate.
Extracted PersistentPropertyPath creation into a dedicated factory class so that it can be tested individually. DefaultPersistentPropertyPath now exposes a ….containsPropertyOfType(…) to detect whether we've already processed a particular type in the path. Also applied a bit of Java 8 and Lombok polish.
InvalidPersistentPropertyPath now collects suggested alternatives to create a better exception message. PersistentEntities now allows to map over a MappingContext and PersistentEntity that a given type is corresponding to. Streamable now exposes an ….isEmpty(). Removed references to equivalent methods implemented in subtypes.
We now check that fragment implementations created via RepositoryFragment.implemented(Class<T>, T) are a subtype of the given class. This assertion raises an exception that prevents errors during runtime.
This change addresses an issue with customized intermediate base repositories in combination with ambiguous naming of implementations. Method invocations fail if a repository derives from a customized base repository interface that implements e.g. CrudRepository and there's an implementation matching the base repository name followed by the implementation suffix. We assume in that case, the implementation contains implementations of the methods declared in the customized base interface.
Original pull request: #280.
Introduce create(…) method as utility that centralizes code that would live in the modules otherwise. This method is a shortcut that creates the repository factory using Supplier, configures the factory with CdiRepositoryConfiguration settings, collects repository fragments and creates the actual repository implementation.
Related pull request: #272.
We now explicitly check for an enum type in SimpleTypeHolder.isSimpleType(…) and resort to true immediately. Before that an enum implementing an interface could have seen a false for the actual enum type in case the interface type had been checked first and (correctly) produced a false. In the check for the actual enum type, depending on the iteration order through the cached values we could've hit the cached false for the interface or the cached true value for Enum.
As a consequence of our renaming efforts in CRUD methods, we lost some generics lookup information to distinguish deleteById(ID) from delete(T) solely based on the method parameter type in case of an intermediate generic repository redeclaring the method as the bound is now expanded to Object and not Serializable, as it did in 1.x.
We now rather check for the method name ending in …ById which is much simpler anyway.
We now make sure that type expressions cannot be used in SpEL expressions handled by MapDataBinder. They're gonna be rejected by considering the property not writable. SpEL expression evaluation errors are now forwarded as NotWritablePropertyException to make sure the failure gets handled as if the property referred to doesn't exist.
We now extended CDI repository configuration to allow configuration of EvaluationContextProvider, NamedQueries, QueryLookupStrategy keys and the repository base class. CdiRepositoryConfiguration is now an interface with default-methods only providing default configuration values.
Original pull request: #272.
Revision and RevisionMetadata now have methods returning Instant instead of LocalDateTime. The existing methods returning LocalDateTime are now deprecated.
Original pull request: #270.
Removed unnecessary imports. Tiny refactoring to pull exception creation into static helper method. Made methods static in test cases where possible.
Original pull request: #273.
Using Instant as internal data type since it's a point in time without time zone which LocalDateTime isn't. Added necessary converters. Fixed one JodaTime converter that used UTC to use SystemDefault like other similar converters.
In case of a conversion failure the error message now contains the source type.
Original pull request: #273.
If a query method now uses e.g. a Vavr Set as return type, we now also use a potential source List as input for the LinkedHashSet, even if that changes the characteristics (duplicate policy etc.) of the result. This is consistent with our general handling of collections as we're using a Spring ConversionService for collection mapping anyway.
In general the new conversion algorithm is driven by the expected target type first:
- i.v.c.Seq -> i.v.c.List
- i.v.c.Set -> i.v.c.LinkedHashSet
- i.v.c.Map -> i.v.c.LinkedHashMap
If none of the declared types is assignable we fall back to the previous algorithm choosing an implementation as close as possible to the original source value:
- j.u.List -> i.v.c.List
- j.u.Set -> i.v.c.LinkedHashSet
- j.u.Map -> i.v.c.LinkedHashMap
Removed some obsolete full qualifications of types.
We now prevent the superfluous creation of a MethodParameter and TypeDescriptor instance in repository method execution in case the value to be returned already is an instance of the expected method return type.
Moved PropertyDescriptor lookup into dedicated subclass to group functionality around the type and MethodsMetadata instances. Extracted individual stream handling steps into dedicated methods for better understandability.
Moved MethodsMetadataReader into classreading package for symmetry with Spring Framework's metadata arrangement. Removed manually declared getters in DefaultMethodsMetadataReader in favor of Lombok getters. Inlined MethodsMetadataReadingVisitor into DefaultMethodsMetadataReader as it's only used there.
Original pull request: #263.
We now provide MethodsMetadataReader to read method metadata from a class file. MethodMetadata is read for all user-declared methods except for constructors (which are technically methods, too).
MethodsMetadataReaderFactory factory = new MethodsMetadataReaderFactory();
MethodsMetadataReader metadataReader = factory.getMetadataReader("com.acme.Foo");
MethodsMetadata metadata = metadataReader.getMethodsMetadata();
This new API is now used by DefaultProjectionInformation to make sure the order of input properties is based on the declaration order in the projection interfaces. Previously that order could not be guaranteed to be stable.
Original pull request: #263.
Expanded generics to make sure we can take Functions and Suppliers of sub- and supertypes properly. Added factory method to create a Lazy from a fixed value. Added method to access Optional result. Added methods to allow chaining Lazy instances via ….or(…). Reduced visibility of ….orElseGet(…) as it basically equates to ….or(…).get(Optional)().
More unit tests.
Introduced BeanLookup to easily create a Lazy<T>-based lookup of a unique bean by type on a ListableBeanFactory. This is in support of making it easy for downstream Spring Data modules to consume the EntityPathResolver declared in an ApplicationContext using XML configuration.
QuerydslWebConfiguration now uses a plain ObjectProvider to access the bean defined falling back to our default.
Original pull request: #265.
We now deploy a custom BeanPostProcessor to customize RequestMappingHandlerAdapter instances by prepending a ProxyingHandlerMethodArgumentResolver (requiring a @ModelAttribute) to the list of resolved HandlerMethodArgumentResolvers to make sure the settings defined in the annotation are applied but the projecting way of data binding is still used.
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 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.
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.