Commit Graph

77 Commits

Author SHA1 Message Date
Mark Paluch
1969f4bcdc DATACMNS-1459 - Update copyright years to 2019. 2019-01-02 12:12:19 +01:00
Oliver Drotbohm
4537c11eba DATACMNS-1440 - Added converters to parse LocalDate(Time) and Instant from their toString() representation. 2018-12-08 12:28:00 +01:00
Mark Paluch
596b0d8177 DATACMNS-1422 - Fall back to reflection-based PropertyAccessor/EntityInstantiator on inaccessible framework types.
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.
2018-11-23 15:19:54 +01:00
Mark Paluch
2c6831948f DATACMNS-1401 - Provide context class on runtime class definition.
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.
2018-10-08 13:53:18 +02:00
Oliver Gierke
dfd2781c76 DATACMNS-1396 - Polishing.
Original pull request: #319.
2018-10-08 13:53:18 +02:00
Mark Paluch
7c9d44659b DATACMNS-1396 - Use best-effort caching in CustomConversions and DefaultTypeMapper.
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.
2018-10-08 13:53:08 +02:00
Mark Paluch
fc4b2d1deb DATACMNS-1402 - Fix invocation of default Kotlin constructor.
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.
2018-10-04 14:38:28 +02:00
Mark Paluch
9478441dbd DATACMNS-1373 - Use ReflectUtils.defineClass(…) to load generated EntityInstantiators.
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.
2018-08-17 12:56:08 +02:00
Oliver Gierke
60bbc59054 DATACMNS-1366 - Performance improvements in CustomConversions.
Removed Optional wrapping for ConcurrentHashMap values in favor of using Void.class as null object. Avoid use streams and removed (repeated) non-null assertions in private methods. Benchmark numbers for calling ….hasCustomReadTarget(…) when non actually exists showing a 5 to 10% increase in performance:

Before:

Iteration   1: 41433276.537 ops/s
Iteration   2: 43991315.457 ops/s
Iteration   3: 45322063.260 ops/s
Iteration   4: 44906183.709 ops/s
Iteration   5: 45378084.579 ops/s
Iteration   6: 44912727.364 ops/s
Iteration   7: 45588155.896 ops/s
Iteration   8: 45453353.185 ops/s
Iteration   9: 45558273.633 ops/s
Iteration  10: 45473310.099 ops/s

After:

Iteration   1: 48979746.822 ops/s
Iteration   2: 48438497.338 ops/s
Iteration   3: 48627686.004 ops/s
Iteration   4: 48815459.842 ops/s
Iteration   5: 48004993.191 ops/s
Iteration   6: 48566871.366 ops/s
Iteration   7: 48604435.350 ops/s
Iteration   8: 47543377.257 ops/s
Iteration   9: 48250165.369 ops/s
Iteration  10: 47845463.861 ops/s
2018-08-16 08:58:07 +02:00
Mark Paluch
79119000bb DATACMNS-1322 - Add support for Kotlin's copy(…) method.
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) {
}
2018-07-04 16:59:51 +02:00
Mark Paluch
53560e0979 DATACMNS-1338 - Calculate defaulting mask count in Kotlin default constructor resolution.
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.
2018-06-10 17:22:17 +02:00
Oliver Gierke
0341f60c7c DATACMNS-1336 - Avoid warning logs for JodaTime and ThreeTenBP converter registrations.
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.
2018-06-06 14:05:06 +02:00
Mark Paluch
4a7bb4853b DATACMNS-1294 - Enforce JSR-310 type mapping to java.util.Date.
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.
2018-04-19 09:56:14 +02:00
Oliver Gierke
6675e33233 DATACMNS-1259 - Polishing.
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.
2018-02-15 14:31:33 +01:00
Jens Schauder
5251f72e69 DATACMNS-1259 - Fixed support for Long values in Auditables.
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.
2018-02-15 14:31:33 +01:00
Oliver Gierke
24a9493fa6 DATACMNS-1243 - Polishing.
Imports and author tags.

Original pull request: #268.
2018-02-01 10:55:34 +01:00
Jens Schauder
58b0cc9c0a DATACMNS-1243 - Add converters from LocalDateTime to Instant and back.
This allows usage of Instant for AuditAware.

Original pull request: #268.
2018-02-01 10:55:34 +01:00
Mark Paluch
51e7e1b7f5 DATACMNS-1240 - Update copyright years to 2018.
Also, remove some trailing whitespaces and align outdated license header format.
2018-01-08 16:04:34 +01:00
Oliver Gierke
d2008ea3b7 DATACMNS-1200 - Polishing.
Left-over whitepspace.

Original pull request: #255.
2017-10-19 12:11:06 +02:00
Mark Paluch
cf5af6a971 DATACMNS-1200 - Fix entity instantiation of Kotlin types using primitives with default values.
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.
2017-10-19 12:01:34 +02:00
Mark Paluch
506fe37aea DATACMNS-1200 - Polishing.
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.
2017-10-19 12:01:28 +02:00
Mark Paluch
78bd8fb0f7 DATACMNS-1200 - Guard casts to primitive type in ClassGeneratingEntityInstantiator.
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.
2017-10-19 12:01:06 +02:00
Mark Paluch
2b4ef1a555 DATACMNS-1175 - Remove argument array caching from EntityInstantiators.
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.
2017-09-27 10:55:34 +02:00
Mark Paluch
d9d0d594e5 DATACMNS-1171 - Limit Kotlin reflection support to regular classes.
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.
2017-09-25 12:23:30 +02:00
Oliver Gierke
22b6971318 DATACMNS-1126 - Polishing.
Moved PreferredConstructorDiscoverers into PreferredConstructorDiscoverer to hide more API. Renamed ClassGeneratingKotlinEntityInstantiator to KotlinClassGeneratingEntityInstantiator.

Use org.springframework.util.Assert instead of com.mysema.commons.lang.Assert.

Original pull request: #233.
2017-08-25 15:00:45 +02:00
Mark Paluch
22b37800ec DATACMNS-1126 - Add class-generating entity instantiation support for Kotlin.
We now discover Kotlin constructors and apply parameter defaulting to allow construction of immutable value objects. Constructor discovery uses primary constructors by default and considers PersistenceConstructor annotations.

KotlinClassGeneratingEntityInstantiator can instantiate Kotlin classes with default parameters by resolving the synthetic constructor. Null values translate to parameter defaults.

class Person(val firstname: String = "Walter") {
}

class Address(val street: String, val city: String) {

	@PersistenceConstructor
	constructor(street: String = "Unknown", city: String = "Unknown", country: String) : this(street, city)
}

Original pull request: #233.
2017-08-25 13:04:28 +02:00
Oliver Gierke
049970874d DATACMNS-1114 - Introduced usage of nullable annotations for API validation.
Marked all packages with Spring Frameworks @NonNullApi. Added Spring's @Nullable to methods, parameters and fields that take or produce null values. Adapted using code to make sure the IDE can evaluate the null flow properly. Fixed Javadoc in places where an invalid null handling policy was advertised. Strengthened null requirements for types that expose null-instances.

Removed null handling from converters for JodaTime and ThreeTenBP. Introduced factory methods Page.empty() and Page.empty(Pageable). Introduced default methods getRequiredGetter(), …Setter() and …Field() on PersistentProperty to allow non-nullable lookups of members. The same for TypeInformation.getrequiredActualType(), …SuperTypeInformation().

Tweaked PersistentPropertyCreator.addPropertiesForRemainingDescriptors() to filter unsuitable PropertyDescriptors before actually trying to create a Property instance from them as the new stronger nullability requirements would cause exceptions downstream.

Lazy.get() now expects a non-null return value. Clients being able to cope with null need to call ….orElse(…).

Original pull request: #232.
2017-07-24 10:47:28 +02:00
Oliver Gierke
6a6d995eab DATACMNS-1109 - Reinstantiate support for all date/time APIs in auditing.
Re-enabled test cases for handling of different date/time APIs in auditing. Tweaked the lookup of the last modified value to try to convert to LocalDateTime as well in case it's a subtype of the type requested. In combination with two newly introduced converters for local date type times in JodaTime and ThreeTenBP, this allows us to still convert legacy JodaTime and ThreeTenBP types to be used as well.
2017-07-12 19:17:23 +02:00
Mark Paluch
3dbbb15672 DATACMNS-1101 - Use dedicated type to cache custom conversion targets without requested target type.
We now use a marker interface to store cache hits for conversion targets without requesting a conversion target in the conversion query. The dedicated marker type has an individual cache view and does not interfere with other types.

Previously we used Object as cache key which caused false positives due to assignability checks. If an earlier conversion query with a requested target type yielded a hit (e.g. negative hit), subsequent queries without a target type received the same answer. This might happen although the non-cached answer would return a different result.
2017-07-04 14:30:45 +02:00
Mark Paluch
8c499122c7 DATACMNS-1101 - Alias is no longer based on Optional.
Remove internal Optional usage from Alias so it's a pure value object that does not create Optional instances during its usage.
2017-07-04 14:30:43 +02:00
Mark Paluch
17b82cfe37 DATACMNS-1101 - Use construction object array pooling.
Use a thread-local object pool for constructor arguments to reduce object allocations.
2017-07-04 14:30:43 +02:00
Mark Paluch
e6e3290e59 DATACMNS-1101 - Refactor CustomConversion to use two-level caching.
We now use a two-level cache instead of using a composite cache key to reduce object allocations.
2017-07-04 14:30:43 +02:00
Mark Paluch
6495a50df7 DATACMNS-1101 - Replace ArrayList indirections in ReflectionEntityInstantiator/PreferredConstructor.
Iterate over simple ArrayList and construct array of params instead of copying elements between multiple Lists.
2017-07-04 14:30:43 +02:00
Mark Paluch
ce9aae49c8 DATACMNS-1101 - Use non-capturing lambdas in CustomConversions for conversion lookup. 2017-07-04 14:30:43 +02:00
Mark Paluch
6c65c02e78 DATACMNS-1101 - Remove Optional from mapping/convert use except for caching of absence and computations that are used to populate caches. 2017-07-04 14:30:42 +02:00
Mark Paluch
74fbe13f54 DATACMNS-1101 - Reduce Optional usage in convert/mapping packages.
Reducing Optional usage that lies on hot code paths for object mapping.
2017-07-04 14:30:42 +02:00
Oliver Gierke
97bd85e628 DATACMNS-1095 - Made ObjectInstantiator public to avoid IllegalAccessErrors.
ObjectInstantiator needs to be declared public as otherwise loading the implementation class fails as it doesn't have access to the (package) private interface in a different classloader.
2017-06-21 18:23:04 +02:00
Oliver Gierke
a190c082f7 DATACMNS-1034 - Introduced API to easily register converters using Java 8 lambdas.
Introduced ConverterBuilder which exposes API to register Spring GenericConverters for the use with a store module's CustomConversions. This allows simple registration of such converters using Java 8 lambdas.

ConverterAware converters = ConverterBuilder.reading(String.class, Long.class,
  it -> Long.valueOf(it)).andWriting(it -> Object::toString);

The setup can also be done from the reading side which would just need the method invocations inverted. The resulting ConverterAware will expose the registered converters so that they can be easily handed to a CustomConversions instance. Partial creation of either reading or writing converters is possible, too with the returned instance then only exposing one of the two converters.

CustomConversions now considers ConverterAware and treats them appropriately for ConvertiblePair registration as well as during the registration in the ConversionService. Tweaked parameter types in CustomConversions to rather accept a Collection<?> for the converters (previously List<?>). Also, registerConverterIn(…) now takes a ConverterRegistry over a GenericConversionService. Polished Javadoc and non-null assertions.

Original pull request: #209.
2017-05-05 12:32:19 +02:00
Mark Paluch
b0177b2ab7 DATACMNS-1014 - Polishing.
Remove superfluous static modifier for inner enum types.

Original pull request: #213.
2017-05-03 08:26:00 +02:00
Jens Schauder
6be036af3a DATACMNS-1014 - Removed DateMidnight related converters.
org.joda.time.DateMidnight is deprecated, therefore we drop support for DateMidnight and remove all references to it.

Original pull request: #213.
2017-05-03 08:25:26 +02:00
Oliver Gierke
233fde36b5 DATACMNS-1035 - Moved CustomConversions to Spring Data Commons.
Extracted CustomConversions — whose code has largely been duplicated between the MongoDB, Couchbase and Cassandra modules — into Spring Data Commons. Store-specific extensions can now be contributed via a StoreConversions value type that carries both, store-specific default converters as well as a store-specific SimpleTypeHolder to augment the default list of simple types.

Removed SimpleTypeHolders public default constructor in favour of a protected one and a static DEFAULT instance for plain references.

Original pull request: #210.
2017-04-21 16:49:00 +02:00
Christoph Strobl
be347eaaab DATACMNS-867 - Additional Java 8 language feature cleanup.
Make use of lambdas and method references though out the codebase. Remove no longer required generic type parameters.
Additionally remove unused imports and replace single element list initialization with dedicated singletonList.
Use Assertion overloads taking Supplier for dynamic assertion error messages.
2017-03-24 08:00:43 +01:00
Oliver Gierke
2d282b2d7f DATACMNS-867 - Cleanups. 2017-03-24 08:00:26 +01:00
Oliver Gierke
d4811e29d9 DATACMNS-867 - Second draft. 2017-03-24 08:00:23 +01:00
Oliver Gierke
cc63e5b7a4 DATACMNS-867 - First draft. 2017-03-24 08:00:23 +01:00
Christoph Strobl
3e048a6dca DATACMNS-985 - Remove references to single-argument assertion methods. 2017-01-31 18:10:40 +01:00
Mark Paluch
8bafe7964b DATACMNS-973 - Polishing.
Convert @see http://… links to valid format using @see <a href=…>…</a>.
2017-01-13 08:50:54 +01:00
Oliver Gierke
092972824e DATACMNS-951 - Polishing.
Switched to parameterized tests for newly introduced Converters.

Fixed imports and JavaDoc.

Original pull request: #186.
2016-12-05 09:59:25 +01:00
Barak Schuster
5020c7b8bb DATACMNS-951 - Added Converter implementations for JSR-310 Duration and Period.
Original pull request: #186.
2016-12-05 09:59:25 +01:00
Oliver Gierke
e0d2907905 DATACMNS-815 - Made static type cache non-static in SimpleTypeInformationMapper.
We now use a non-static cache for TypeInformation instances in SimpleTypeInformationMapper to make sure Spring Boot's development tools can correctly reload classes. Removed the static singleton instance of SimpleTypeInformationMapper in favor instantiating it directly.
2016-02-09 14:22:06 +01:00