We now support configuration of the class loader in SimpleTypeInformationMapper to use a configured class loader instead of falling always back to the default/contextual class loader. In arrangements where the contextual class loader isn't able to provide access to the desired classes (e.g. parallel Streams, general Fork/Join Thread usage) the contextual class loader may not have access to the entity types. By implementing BeanClassLoaderAware, we can now propagate a configured class loader.
Closes#2508
We no recognize properties of type org.jmolecules.ddd.types.Association as associations in our PersistentProperty model.
Also, we now register JMolecules Converter implementations for Association and Identifier in CustomConversions so that they can persisted like their embedded primitive value out of the box.
Fixes#2315.
Original pull request: #2316.
Replace the few occurrences where SLF4J was being used directly so that
all logging now happens via commons-logging. The log patterns used in
SLF4J messages have been replaced with `LogMessage` which was introduced
in Spring Framework 5.2.
Original pull request: #448.
Rename static final `CACHE` members to use the lowercase form. Although
the caches are static final, they are not constant values.
Original pull request: #448.
Converting from instant to ZoneDateTime and back to Instant does not seem to have a purpose as the timezone information will never be used
Original pull request: #260.
Joda-Time and ThreeTenBackport converters are now deprecated in favor of JSR-310 (java.time) support. These converters are now in maintenance mode without receiving future enhancements.
Replace list creation with constant. Replace ConverterConfiguration.skipFor list with Predicate for flexible conditions. Fix typo. Simplify conditionals.
Original pull request: #421.
CustomConversions now registers all given user defined converters and selects only those converters from the StoreConversions that convert to or from a store supported simple type.
By doing so we make sure to only register supported converters which removes warning messages from the log and reduces the number of converters within the ConversionService.
Original pull request: #421.
To retain backwards compatibility for the legacy EntityInstantiators API, we now adapt the map values for custom instantiators that are handed into the constructors of EntityInstantiators.
We now ship and use a PropertyAccessor implementation by default that will fall back to use the persistence constructor and creating a new instance to "set" a property. This allows completely immutable types, ommitting previously needed wither methods, e.g. to populate automatically generated identifier values.
This is implemented by using the EntityInstantiator available and a ParameterValueProvider that returns the value of the properties of the current instance but replacing the one for the value to be set. This requires moving EntityInstantiators, the EntityInstantiator SPI as well as all existing implementations (reflective, class generating and the Kotlin one) into the mapping.model package. Legacy instances stay around in deprecated form to avoid breaking existing clients (other store modules as well as user implementations of EntityInstantiator).
The newly introduced implementations stay package protected as their sole users are now colocated in the same package. Access from the legacy types is handled via InternalEntityInstantiatorFactory, which is introduced in deprecated from for removal alongside the actual deprecations.
We now fall back to reflection-based PropertyAccessor/EntityInstantiator strategies when framework types are not visible by the entity's ClassLoader.
Typically, we use class generation to create and load PropertyAccessor and EntityInstantiator classes to bypass reflection. Generated types are injected into the ClassLoader that has loaded the actual entity. Generated classes implement framework types such as ObjectInstantiator and these interfaces must be visible to the ClassLoader that hosts the generated class. Some arrangements, such as OSGi isolate class repositories so the OSGi class loader cannot load our own types which prevents loading the generated class.
Original pull request: #324.
We now provide the context class for private MethodHandle lookup in the context of the actual entity class to properly use MethodHandles.defineClass(…) and to avoid illegal access warnings caused by reflective access to the defineClass(…) method on class loaders.
Also, we now use the internal type name without adding the reference type decorator when casting the result of a wither invocation. CHECKCAST allowed on earlier Java runtimes (version 8 and earlier) to use the reference decorator (L…;) around the type name. Java 9 and newer reject this format with a ClassFormatError.
Original pull request: #318.
We now apply best-effort caching instead of atomic caching for custom conversions and type mapping. This change is a workaround for a Java 8 bug in ConcurrentHashMap where the computeIfAbsent(…) operation unconditionally locks nodes even when the node is already present.
The workaround is to assume the optimistic case by looking up the key and then falling back to computeIfAbsent if the key is absent.
Before:
TypicalEntityReaderBenchmark.simpleEntityReflectivePropertyAccessWithCustomConversionRegistry thrpt 10 6487423,969 ± 349449,326 ops/s
DefaultTypeMapperBenchmark.readTyped thrpt 10 38213392,961 ± 5080789,480 ops/s
DefaultTypeMapperBenchmark.readUntyped thrpt 10 47565238,929 ± 855200,560 ops/s
After:
TypicalEntityReaderBenchmark.simpleEntityReflectivePropertyAccessWithCustomConversionRegistry thrpt 10 7361251,834 ± 278530,209 ops/s
DefaultTypeMapperBenchmark.readTyped thrpt 10 122523380,422 ± 3839365,439 ops/s
DefaultTypeMapperBenchmark.readUntyped thrpt 10 181767673,793 ± 3549021,260 ops/s
Original pull request: #319.
We now correctly calculate the number of defaulting masks used to represent constructor arguments. Previously, we've been one off which caused that Kotlin classes with 32/33 parameters weren't able to be instantiated.
We also now reuse KotlinDefaultMask to apply defaulting calculation and removed code duplicates.
We now use Spring's ReflectUtils.defineClass(…) to load generated EntityInstantiators which uses internally either MethodHandles.Lookup.defineClass(…) (on Java 9 and higher) or reflective defineClass invocation on the originating ClassLoader. Class injection into the originating ClassLoader assigns the ClassLoader of the entity to the generated class which allows optimized instantiation of package-protected classes and constructors.
Original pull request: #308.
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 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.
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.
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.
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.