Kept in a separate commit, so that it's easy to add again by reverting this commit. Removed, as the new behavior is effectively what had been documented as intended behavior all the time.
Original pull request: #248.
We now use FragmentMetadata to control the way fragement interfaces and base packages to scan are calculated. Refactored RepositoryConfiguration.getImplementationBasePackages() to not take a parameter.
Original pull request: #248.
Custom repository implementation scan defaults to the repository interface package and its subpackages and no longer scans all configured base packages. Scan for fragment implementations defaults to the fragment interface package. Using the interface package for scanning aligns the behavior with the documentation.
This default can be changed with @Enable…Repositories annotations that support the limitImplementationBasePackages parameter to scan in repository base packages for custom implementations:
@EnableJpaRepositories(limitImplementationBasePackages = false)
@Configuration
class AppConfiguration {
// …
}
Declaring the implementation along with the interface in the same package is an established design pattern allowing to limit the scanning scope. A limited scope improves scanning performance as it can skip elements on the classpath, that do not provide that particular package.
Previously, we scanned for implementations using the configured base packages that were also used to discover repository interfaces. These base packages can be broader for applications that spread repository interfaces across multiple packages.
When trying to determine if a parameter is a dynamic projection parameter, i.e. the parameter of type Class that determines the projection to use, now the type parameter of that method parameter gets compared with the unwrapped return type. Therefore this works now not only for Maps and Collections but also for the various wrappers defined in QueryExecutionConverters.
Moved the method for unwrapping the return type from AbstractRepositoryMetadata to QueryExecutionConverters in order to make it available to every class needing it. This also puts it closer to the data it is working on.
Original pull request: #250.
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.
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.
We now fall back to default preferred constructor discovery if a Kotlin class has no primary constructor and no preferred constructor is resolved. Previously, primary constructor resolution yielded no result (returned null) which caused the subsequent Java constructor lookup to fail.
Original pull request: #244.
The new name currently delegates to old version, so classes only implementing the old method still work. Old name is deprecated.
Original pull request: #243.
We now validate query method invocations to check method parameters whether they accept null values and reject execution if null values are not supported. We derive nullability support from repository interfaces declared using Kotlin and Spring's NonNullApi/Nullable annotations.
We also check whether a query method can return null. If a query method returns null which isn't supposed to do so, then we throw EmptyResultDataAccessException to prevent null return values.
interface UserRepository extends Repository<User, String> {
List<User> findByLastname(@Nullable String firstname);
@Nullable
User findByFirstnameAndLastname(String firstname, String lastname);
}
interface UserRepository : Repository<User, String> {
fun findByLastname(username: String?): List<User>
fun findByFirstnameAndLastname(firstname: String, lastname: String): User?
}
Original pull request: #241.
We now allow users to use our own Streamable interface as query method return types to easily invoke ….stream() on everything that returns an Iterable using non-parallel streaming by default.
AbstractAggregateRoot is now generified to be able to use its concrete type on methods returning an instance of itself. Added new methods andEvent(…) and andEventsFrom(…) to easily transfer events from another aggregate instance. Added unit tests for fundamental functionality of the base class.
We now prefer to inspect the arguments handed to save(…) methods over inspecting the return value as the invocation of the actual method is free to exchange the instance handed into it and return a completely new one with the events contained in the parameter completely wiped.
We're now trying to look up a uniquely available ObjectMapper instance from the application context falling back to a simple new instance in case none can be found.
We now forward method parameters of methods on projection interfaces to the expression evaluation. The parameters are exposed via an array named "args".
Add Nullable annotation to ParsingUtils, Sort.Order and PropertyValueProvider.
Add getRequiredAnnotation(…) to PersistentEntity and PersistentProperty to provide methods returning required, non-null annotations.
We filter interfaces annotated with @NoRepositoryBean from fragment interface candidates and not longer scan for implementations of these.
Extending a base repository usually requires an interface which is used as base interface instead of Repository/CrudRepository in user repositories. If the naming scheme of the extended interface and the implementation fits to fragment interfaces, then we previously registered the class additionally as fragment implementation. The bean registration caused container startup failures because of unsatisfied dependencies or would shadow the base repository implementation.
Original pull request #239.
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.
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.
We turned Example and ExampleMatcher into interfaces with default implementations created via the static of methods. The default ExampleMatcher has strongly typed default implementation. This change allows store implementations to create their very own flavor of Example and ExampleMatcher allowing eg. non typed ones.
Original pull request: #238.
Path expressions are now evaluated one by one with the first one actually available in the payload being used for value lookup. Also tweaked the default behavior to return null in case of an single, invalid path.
Methods for domain event registration and access are now not following bean semantics anymore to avoid those accidentally leaking into formats that use the bean spec (e.g. Jackson to produce JSON).
We're now favoring the generic TypeInformation over trying to resolve the property type via field or PropertyDescriptor as only the former does proper generic type resolution.
Type specialization - i.e. enrichment of a raw type with a current generic context - is now only done if the current type is not yet resolved completely. This allows wildcarded target references to just fall back to the type to specialize, which will then by definition carry more generics information than the one to be specialized.
Revert the merging of a parent type's type variable map and only apply the locally available declared generics in case of parameterized types. Moved that augmentation into ParameterizedTypeInformation.
We now use CGLibs ReflectUtils.defineClass(…) to inject classes into the entity's class loader instead of our own code. ReflectUtils itself discovers whether the class loader is encapsulated and falls back to Unsafe for class definition. We no longer require our own code so the evil class was removed.
Original pull request: #234.
RxJava 1 development is phased out over time (Feature freeze in June 2017, EOL in March 2018) and we don't want to ship newly developed first-class support for libraries known to be no longer maintained. RxJava 1 type adoption support is not affected. Single and Observable can be still used in user-space code declaration, also copies of RxJava1CrudRepository (in user-space code) remain working.