This is needed for downstream projects that attempt to merge persistent entity instances and previously didn't have a chance to detect that an object had to be set as-is instead of being merged recursively.
PersistentPropertyAccessor is now generic to be able to retain the type information about the object it was created for and the return type of ….getBean(). Adapted client APIs.
As setting a PersistentProperty can actually change the object that the property is changed on, we now recursively traverse property paths up as longs as the setting of the property results in the bean not being replaced.
We've changed the APIs in the auditing subsystem so that we support immutable entities, mostly through MappingAuditableBeanWrapperFactory that uses a PersistentPropertyAccessor.
Add missing since tags. Extract methods to maintain single abstraction level per method. Move visitDefaultValue from ClassGeneratingPropertyAccessorFactory to BytecodeUtil. Extend Javadoc.
We now support updating of immutable Kotlin data objects by creating new copies through Kotlin's copy method that is generated along with data classes and immutable properties.
data class DataClassKt(val id: String) {
}
data class ExtendedDataClassKt(val id: String, val name: String) {
}
We now detect withher methods (withId(…)) that create a new object instance that contains the new property value. We support those wither methods to create new object instances from property updates. Classes following a wither pattern declare a withXXX(…) method that accepts the property value and return a new, instance of its own type associated with the property value. Along with this change we removed the ability to update final fields that worked by accident using reflection.
class ValueClass {
@Wither String id;
}
class ValueClass {
final String id;
ValueClass withId(String id) {
return new ValueClass(id);
}
}
We now calculate the number of expected default masks to filter synthetic constructors that do not match the expected parameter count. A Kotlin constructor with argument defaulting generates a synthetic integer argument for every 32 constructor arguments. This is independent of the number of actual optional arguments.
Previously, we used an non-exact check to consider constructors as default ones if they had at least two additional arguments. This caused the wrong constructor being used if the non-synthetic types matched the types of the default constructor.
Removed the explicit registration for JodaTime and ThreeTenBP to JSR-310 converters (originally introduced to support the unifying lookup of the last modified date in the auditing subsystem) as reading converters. This avoids the warning reporting that the source types (JodaTime and ThreeTenBP LocalDateTime) not being store-native types (which usually indicates a superfluous converter registration).
Updated the test cases to make sure these warnings aren't trigger due to test setups causing the same issue.
Moved test cases into PropertyPathUnit test so that they're closer to the implementation. Switched to Introspector.decapitalize(…) to follow the Java Beans Specification regarding the handling of all-uppercase properties.
Original pull request: #289.
PersistentEntity now exposes an ….isNew(…) method that exposes the same detection algorithm previously exposed through MappingContextIsNewStrategyFactory (Persistable in favor of the version property in favor of an identifier lookup). MappingContextIsNewStrategyFactory has been refactored to return an ad-hoc strategy to delegate to the newly introduced method.
The core message to implementing modules is that they should now prefer PersistentEntityInformation within their RepositoryFactorySupport implementation and move all customizations made in the store-specific EntityInformation implementation in PersistentEntity.
We now support the use of Vavr's Try as repository method return type so that exceptions caused by the repository method execution are wrapped into a Failure. Introduced a return type specific indirection of the execution. We now also recursively handle wrapper types so that Try<Option<…>> is valid, too.
Added support for Javaslang's Try, too.
We now expose what type or PersistentEntity an association points to by trying to match the association's type to identifier types to entities. In case multiple matches are found, we require the user to explicitly declare the target type via @Reference.
Introduced PersistentEntities.of(…) for convenience.
Introduced ProxyUtils.getUserClass(…) that by default is basically a facade for Spring's ClassUtils.getUserClass(…) but allows the registration of ProxyDetector implementations via Spring's SpringFactoriesLoader mechanism.
Moved all existing usages of ClassUtils.getUserClass(…) to ProxyUtils.
Moved newly introduced types into the ….data.repository.query package as the parser one contains types that parses queries from method names. Simplified the API surface by hiding SpelExtractor completely and making the API on SpelQueryContext more convenient to directly create a SpelEvaluator.
The goal is to extract the parts of query parsing that are generic into commons in order to avoid slightly different behavior in modules.
Extracted the QuotationMap from Spring Data JPA as well as the part of the parser that deals with extracting SpEL expressions.
Added the SpelEvaluator for evaluating the SpEL expressions.
Added enough configurability to satisfy the needs of Neo4j and JPA.
Mainly to support the different formats for bind parameter :name vs {name}.
We now have a refined replica of the EvaluationContextProvider API and SPIs in the org.springframework.data.spel package. It has seen a bit of a Java 8 overhaul by removing the SPI support class in favor of turning most methods in EvaluationContextExtension into default ones.
The already existing API has been renamed to QueryMethodEvaluationContextProvider to indicate it's working with additional semantics specific to query methods (i.e. the Parameters metadata). The internals have been refactored to use the new API but still detect implementations of the old EvaluationContextExtension interface. The implementations get wrapped into an adapting proxy to satisfy the new API so that the actual inspection and usage of the extension is now already done using the new APIs.
The repository configuration has slightly change so that the creation of the EvaluationContextProvider is now taking place within RepositoryFactoryBeanSupport's implementation of BeanFactoryAware.
AbstractMappingContext is now ApplicationContextAware and holds an ExtensionAwareEvaluationContextProvider using the configured ApplicationContext. That EvaluationContextProvider is forwarded to all MutablePersistentEntity instances. BasicPersistentEntity now exposes getEvaluationContext(…) to subclasses to easily create an EvaluationContext using the extension aware infrastructure.
Removed DefaultEvaluationContextProvider in favor of a simple constant in QueryMethodEvaluationContextProvider.
Related tickets: DATACMNS-1258, DATACMNS-1108.
We now explicitly disable entity expansion in the DocumentBuilderFactory used by XMLBeam.
Introduced constructor in XmlBeamHttpMessageConverter to allow dedicated configuration of an XBProjector instance in case the defaults need tweaking and augmented the web configuration setup to automatically pick up a custom XmlBeamHttpMessageConverter bean instead of our own default if present.
After considering JSR-310 types to be simple we map these types primarily to java.util.Date as the majority of stores does not natively support JSR-310 types. Converters referencing JSR-310 types are now properly annotated with Reading/WritingConverter annotations to distinguish between reading and writing intents.
Othwerise, converters between JSR-310/java.util types and Joda/ThreeTenBackport to JSR-310 types interfere with conversion as regular java.util.Date types would convert to e.g. LocalDateTime.
We now consider all types in the java.time package as simple types to prevent deep reflective access. We are already excluding java.lang types for the same reason.
Original pull request: #286.
Previously a custom Iterable implementation would've caused QueryMethod.isCollectionQuery() to return true. We now solely rely on TypeInformation.isCollectionLike() (which checks for exact Iterable, Collection assignability and arrays) after handling potential wrapper types.
Instead of a simple check for assignability from Iterable, we now properly use TypeInformation.isCollectionLike(), which checks for Iterable equality or assignability of collections or arrays as well as an explicit check for Slice as that is needed to properly unwrap Page instances and Slices themselves. That prevents custom domain types implementing Iterable from being unwrapped into their element types.
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.
Use ConcurrentHashMap in AnnotationBasedPersistentProperty for thread-safe annotation caching. Reintroduce eager cache check to prevent lambda instances on positive cache hits.
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.
Fixed nullability constraints on method RepositoryConfigurationExtensionSupport.loadRepositoryInterface(…). Tweaked method declaration order to have public methods first, protected methods after that. Fixed a tiny typo.
Original pull request: #276.