We now use HashMap to store persistent properties of a PersistentEntity. An entity is built in a single thread so no concurrent modification happens. Concurrent reads may happen during entity usage which is fine as the PersistentEntity is not changed anymore. Previously, we used ConcurrentReferenceHashMap defaulting to soft references. Soft references can be cleared at the discretion of the GC in response to memory demand. So a default ConcurrentReferenceHashMap is memory-sensitive and acts like a cache with memory-based eviction rules.
Persistent properties are not subject to be cached but elements of a PersistentEntity and cannot be recovered once cleared.
Original pull request: #304.
CustomRepositoryImplementationDetector now works in two differend modes. If initialized with an ImplementationDetectionConfiguration, it will trigger a canonical, cached component scan for implementation types matching the configured name pattern. Individual custom implementation lookups will then select from this initially scanned set of bean definitions to pick the matching implementation class and potentially resolve ambiguities.
We now eagerly look up the aggregate root type of a repository in the MappingContext. Some implementations might not have pre-populated the context with all entities and we need to make sure it knows about the aggregate root as other clients (e.g. the auditing subsystem) might only defensively access the entities via PersistentEntities which is not adding new entities to avoid store clashes.
Added debug logging in RepositoryFactorySupport and RepositoryConfigurationDelegate so that the scanning and the instantiation of repositories can be a lot easier identified in the logs.
The newly introduced method indicates whether any properties have to be populated to create instances of the entity. This is useful for objects that are completely initialized through their constructors as converters then can avoid iterating over all properties just to find out none of them have to be populated.
The exception messages used in the PersistentProperty.getRequired(Getter|Setter|Wither|Field)(…) now mention the name of the property that's offending.
ProxyProjectionFactory and ResultProcessor require a DefaultConversionService to convert values for projection proxies and to post-process query method results. Creating instances of these types requires an instance of the conversion service which previously created a DefaultConversionService instance (along all converter registrations) upon ProxyProjection/ResultProcessor instantiation.
We now use the shared instance that is initialized once and shared across all ProxyProjection/ResultProcessor instances to reduce garbage and improve the CPU profile.
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.