Commit Graph

850 Commits

Author SHA1 Message Date
Mark Paluch
caaec1b862 DATACMNS-1415 - Use thread-safe caching in SpelAwareProxyProjectionFactory.
We now use ConcurrentHashMap as type instead of HashMap to properly synchronize concurrent updates to missing cache elements.

The previously used HashMap was not thread-safe so concurrent modifications resulted in ConcurrentModificationException.
2018-11-12 16:01:21 +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
42ee9448d9 DATACMNS-1400 - Do not consider bridge modifier in Kotlin default-method discovery.
We now no longer consider bridge modifiers when looking up Kotlin default methods. We previously included checks whether a synthetic default method is also a bridge method to take all specifics of synthetic methods into account. With Kotlin 1.3, the compiler no longer sets the bridge flag. This behavior change would previously prevent usage of the copy method with classes compiled with Kotlin 1.3.

Default method discovery is still guesswork and Kotlin compiler reverse engineering as there is no documentation on how to look up this kind of methods.

Further references:
* https://youtrack.jetbrains.net/issue/KT-24415 - Remove bridge flag from default methods.
* https://youtrack.jetbrains.net/issue/KT-27317 - No documented rules for discoverability of generated methods.
2018-10-04 10:59:23 +02:00
Vjkumar Bokar
47283aa47a DATACMNS-1399 - Fixed error message in repository fragment initialization.
Swapped parameters to match the placeholder semantics in the actual error message.

Original pull request: #313.
2018-10-01 10:16:11 +02:00
Mark Paluch
7eacab6a34 DATACMNS-1391 - Use prefered constructors to discover Kotlin's copy method.
We now use the primary constructor of Kotlin classes to discover the copy method. We use the primary constructor args to compare signatures and only use the copy method that takes all parameters in the constructor args order. This allows to find the appropriate copy method in case the class declares multiple copy methods.

We now also cache the copy method (KCallable) to reduce lookups in BeanWrapper.

Original pull request: #312.
2018-09-18 18:34:57 +02:00
Tobias Hermann
6297e4b6d1 DATACMNS-1392 - Fix typo in Parameters.getParameter(…) exception message.
Original pull request: #311.
2018-09-13 14:17:32 +02:00
Mark Paluch
d5761c7c8d DATACMNS-1389 - Reorder repository candidate check.
We now check whether to use the repository configuration as last check to clarify store module responsibility first. This allows to place store-specific checks in RepositoryConfigurationExtensionSupport.useRepositoryConfiguration(…) such as rejecting reactive repositories for a store module that does not support reactive repositories

Previously, we called useRepositoryConfiguration(…) before checking whether the actual repository interface is handled by the store module. This resulted in rejection of reactive repositories by store modules that do not provide reactive support whereas the repository did not belong to the actual store module.

Related ticket: DATACMNS-1174.
2018-09-10 12:12:49 +02:00
Yuki Yoshida
aa3ed766b5 DATACMNS-1387 - Fix JavaDoc in CurrentDateTimeProvider and remove unused import. 2018-09-07 13:21:47 +02:00
Oliver Gierke
8b6cc3af11 DATACMNS-1386 - Avoid strong type dependency to Jackson in SpringDataWebConfiguration.
We now avoid using a Lambda to provide a default ObjectMapper instance in the code that's reflectively guarded against Jackson not being present. The lambda causes a method to be generated for the class that will require ObjectMapper to be present on reflection inspection of that method. Switching to a method reference to ObjectMapper's constructor resolves that problem as the indirection via the additional, offending method is not needed.

Further reading: https://www.javabullets.com/how-lambdas-and-anonymous-inner-classesaic-work/
2018-09-07 12:09:29 +02:00
Oliver Gierke
3dacaf64d8 DATACMNS-1384 - Support for j.u.Date and j.s.Timestamp in AnnotationRevisionMetadata.
We now properly convert legacy Date instances into Instants to expose the revision date. Support for Timestamp is transparent as it extends Date.
2018-09-01 18:34:56 +02:00
Oliver Gierke
1d4a53dc28 DATACMNS-1383 - Parameters now properly detects Pageable and Sort extensions.
One of the constructors of Pageable wasn't properly checking for assignability of Pageable parameters to detect them but was expecting Pageable itself being used under all circumstances. This has now been opened up by an assignability check.
2018-08-30 16:04:02 +02:00
Mark Paluch
a37599075f DATACMNS-1174 - Polishing.
Trim trailing whitespaces. Javadoc fixes.
2018-08-29 12:01:31 +02:00
Mark Paluch
ee64225be0 DATACMNS-1174 - Reject reactive repository implementation by default.
We now reject reactive repository metadata by RepositoryConfigurationExtensionSupport.useRepositoryConfiguration(…) assuming that Spring Data modules provide only imperative repository support by default. Reactive store modules are required to override useRepositoryConfiguration(…) anyway to not accidentally implement imperative repositories with a reactive Repository extension.
2018-08-29 12:01:31 +02:00
Oliver Gierke
8e7a27cc72 DATACMNS-1032 - Deprecate UserCredentials. 2018-08-29 11:57:32 +02:00
Oliver Gierke
f00d5b9ac6 DATACMNS-1376 - Polishing.
Moved JVM version lookup into Version.

Original pull request: #307.
2018-08-17 13:09:04 +02:00
Mark Paluch
0d39693c94 DATACMNS-1376 - Fix illegal access warning in DefaultMethodInvokingMethodInterceptor on Java 9 and higher.
We now attempt to use private MethodHandles lookup as the first mechanism to resolve a MethodHandle for default interface methods and fall back to reflection-based Lookup construction if private lookup is not available. Reflective availability is checked lazily to prevent illegal access on enum constant construction. This approach prevents an illegal access which was logged by attempting a reflection-based lookup first.

We also introduced a FALLBACK mechanism to split encapsulated access from a fallback mechanism.

Original pull request: #307.
2018-08-17 13:08:30 +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
b0eb0c47d2 DATACMNS-1377 - ConvertingPropertyAccessor now properly coverts values for property paths.
Previously, ConvertingPropertyAccessor did not override PersistentPropertyAccessor.setProperty(PersistentPropertyPath, Object), so that the target value had to be of the leaf property's type. We now implement that method and convert it into that type before invoking the super method.
2018-08-17 11:47:31 +02:00
Oliver Gierke
14c2b5b766 DATACMNS-1375 - AnnotationRepositoryMetadata now exposes the offending repository name. 2018-08-16 14:06:01 +02:00
Oliver Gierke
22a6870d5c DATACMNS-1367 - Improved repository bootstrap logging.
Core information about the bootstrap mode, timing and number of repositories created is now logged in info. Individual repository registration is logged in trace now.

Related tickets: DATACMNS-1368.
2018-08-16 14:03:47 +02:00
Oliver Gierke
5da6cf20a2 DATACMNS-1368 - Add support for deferred repository initialization.
Both the XML and annotation based configuration sources now support a bootstrap mode configuration property that allow to configure whether repositories are eagerly initialized unless declared as lazy, initialized in a deferred way (just before the application context finishs bootstrapping) or entirely lazy (upon first usage, i.e. a method invocation).

We now register a custom AutowireCandidateResolver that will consider all injection points of lazy repositories lazy too. This will prevent them to accidentally trigger downstream infrastructure initialization.
2018-08-16 12:16:40 +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
4600190d01 DATACMNS-1366 - Performance improvements in mapping subsystem
We now use a presized HashMap and Weak references in BasicPersistentEntity to improve memory and CPU profile and and avoid unmodifiable collection creation in BasicPersistentEntity.iterator(). Refactored ClassTypeInformation.from(…) lambda to method reference and predefined collection size for the cache. Reduced object instantiations during TypeDiscoverer.equals(…) by checking for type variable map emptiness to avoid Map iterator creation in Map.equals(…).

Original pull request: #305.
2018-08-15 15:13:41 +02:00
Mark Paluch
e50e013964 DATACMNS-1364 - Polishing.
Use weak references in annotation and property annotation cache to retain references until the last GC root is cleared. Remove trailing whitespaces. Reformat.

Original pull request: #304.
2018-08-15 09:51:17 +02:00
Mark Paluch
7d3222320c DATACMNS-1364 - Store persistent properties in HashMap.
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.
2018-08-15 09:50:48 +02:00
Oliver Gierke
13b115068d DATACMNS-1371 - Improvements to custom implementation scanning.
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.
2018-08-14 15:25:30 +02:00
Oliver Gierke
3f613ff13f DATACMNS-1370 - Avoid superflous, regex-based type check while scanning for custom implementations. 2018-08-09 13:05:44 +02:00
Oliver Gierke
084b46036a DATACMNS-1369 - RepositoryFactoryBeanSupport now adds the aggregate root type to the MappingContext.
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.
2018-08-09 12:09:54 +02:00
Oliver Gierke
1984fbdb56 DATACMNS-1367 - Improved debug logging to better identify scanning and initialization of repositories.
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.
2018-08-09 08:14:11 +02:00
Oliver Gierke
f72b446361 DATACMNS-1366 - Polishing. 2018-08-08 13:16:06 +02:00
Oliver Gierke
14fbc11f00 DATACMNS-1366 - Introduce PersistentEntity.requiresPropertyPopulation().
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.
2018-08-08 13:16:05 +02:00
Oliver Gierke
57d0b322e6 DATACMNS-1359 - Improved exception message for missing accessors and getters.
The exception messages used in the PersistentProperty.getRequired(Getter|Setter|Wither|Field)(…) now mention the name of the property that's offending.
2018-08-06 12:45:43 +02:00
Mark Paluch
ea8cf8c629 DATACMNS-1357 - Use shared DefaultConversionService in ProxyProjectionFactory and ResultProcessor.
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.
2018-07-25 15:31:45 +02:00
Oliver Gierke
31a08254a7 DATACMNS-1354 - BasicPersistentEntity now exposes means to override the fallback IsNewStrategy.
This is useful in case a particular store implementation needs to customize the default is new detection.
2018-07-12 12:18:29 +02:00
Oliver Gierke
3c2522df9a DATACMNS-1322 - Added @Immutable to allow users to express a persistent entity to be considered immutable.
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.
2018-07-12 10:26:16 +02:00
Oliver Gierke
1f4d494f83 DATACMNS-1322 - Generified PersistentPropertyAccessor API.
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.
2018-07-12 10:23:17 +02:00
Oliver Gierke
d1ebfcfc5e DATACMNS-1322 - Add support for immutable entities in PersistentPropertyAccessor.setProperty(PersistentPropertyPath, Object).
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.
2018-07-04 16:59:51 +02:00
Oliver Gierke
6cb3587ba3 DATACMNS-1322 - Adapt auditing handler API to support immutable entities.
We've changed the APIs in the auditing subsystem so that we support immutable entities, mostly through MappingAuditableBeanWrapperFactory that uses a PersistentPropertyAccessor.
2018-07-04 16:59:51 +02:00
Mark Paluch
85b507ce10 DATACMNS-1322 - Cleanup refactorings.
Add missing since tags. Extract methods to maintain single abstraction level per method. Move visitDefaultValue from ClassGeneratingPropertyAccessorFactory to BytecodeUtil. Extend Javadoc.
2018-07-04 16:59:51 +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
80db17d6ba DATACMNS-1322 - Polishing.
Extract utility methods to BytecodeUtil.
2018-07-04 16:59:51 +02:00
Mark Paluch
1ea65f3130 DATACMNS-1322 - Detect wither methods.
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);
	}
}
2018-07-04 16:59:51 +02:00
Oliver Gierke
6951d8b711 DATACMNS-1345 - RepositoryFactoryBeanSupport now properly reports missing MappingContext. 2018-06-21 08:55:45 +02:00
Oliver Gierke
d570f4d79e DATACMNS-1342 - TypeInformation.isCollectionLike() considers Streamable now. 2018-06-14 12:18:41 +02:00
Oliver Gierke
37ab0a5d8f DATACMNS-1341 - ProxyUtils now detects JDK proxy target classes. 2018-06-14 11:51:15 +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