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.
MappingContext now exposes a method to detect all property paths pointing to properties matching a given predicate.
Extracted PersistentPropertyPath creation into a dedicated factory class so that it can be tested individually. DefaultPersistentPropertyPath now exposes a ….containsPropertyOfType(…) to detect whether we've already processed a particular type in the path. Also applied a bit of Java 8 and Lombok polish.
InvalidPersistentPropertyPath now collects suggested alternatives to create a better exception message. PersistentEntities now allows to map over a MappingContext and PersistentEntity that a given type is corresponding to. Streamable now exposes an ….isEmpty(). Removed references to equivalent methods implemented in subtypes.
We now inspect Kotlin's Metadata annotation to determine the kind of a Kotlin class.
Previously we used Kotlins internal API to introspect classes. Because this API is not public and can be changed at any time we rely on Kotlins annotations as they are supposed to not change in near future.
Original pull request: #269.
Expanded generics to make sure we can take Functions and Suppliers of sub- and supertypes properly. Added factory method to create a Lazy from a fixed value. Added method to access Optional result. Added methods to allow chaining Lazy instances via ….or(…). Reduced visibility of ….orElseGet(…) as it basically equates to ….or(…).get(Optional)().
More unit tests.
Introduced BeanLookup to easily create a Lazy<T>-based lookup of a unique bean by type on a ListableBeanFactory. This is in support of making it easy for downstream Spring Data modules to consume the EntityPathResolver declared in an ApplicationContext using XML configuration.
QuerydslWebConfiguration now uses a plain ObjectProvider to access the bean defined falling back to our default.
Original pull request: #265.
We now resolve Kotlin interface properties to inspect these for nullability. Kotlin-reflect does not resolve interface property accessors yet so we need to handle this aspect ourselves.
Related ticket: https://youtrack.jetbrains.com/issue/KT-20768.
Original pull request: #254.
We now eagerly resolve a generics declaration chain, which we previously - erroneously - expected GenericTypeResolver to do for us. Simplified TypeVariableTypeInformation implementation. Renamed ParameterizedTypeUnitTests to ParameterizedTypeInformationUnitTests.
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 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 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.
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.
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.
This is an overload for the already existing method taking a plain Iterator so that we only apply the close callback to the Stream in the newly introduced one.
Updated Sonargraph architecture description. Polished imports in domain package to avoid unnecessary imports (mostly due to Javadoc references).
Removed manually declared constructor in ExampleMatcherAccessor in favor of Lombok's @RequiredArgsConstructor. Removed deprecations in type information subsystem. Moved to different way of class loading to avoid null pointer warnings in ReflectionUtils.
All overloaded methods are now available in SPeL expressions. Among methods with identical argument list from different sources in the same extension (extension, root object, aliases) the last one in the order in parens wins. If there is more than one method for an application the following rules are applied: if there is one method with exact matching types in the argument list it is used, otherwise an exception is thrown.
Original pull request: #217.
RevisionRepository now returns Optional for methods that could previously return null. Revision exposes additional methods to lookup required revision numbers and dates. Revisions now implements Streamable and exposes a ….none() factory method to create an empty instance.
AnnotationBasedRevisionMetadata now uses Lazy to lookup the fields with revision annotations. AnnotationDetectionFieldCallback now also uses Optional in places it previously returned null. StreamUtils now exposes factory methods for Collector instances producing unmodifiable List and Set instances.
Related ticket: DATACMNS-867.
Removed the additional methods that reflectively checked for the Stream type and whether a Method instance is a default method. Turned utility classes into interfaces where possible. Make use of Lombok's @UtilityClass where not.
Removed obsolete implementation class in StreamUtils in favor of a lambda.
Streamable now exposes map(…), flatMap(…) and filter(…) to allow easy conversion into new Streamables. Introduced LazyStreamable to back those implementations. Simplified implementation of methods in PartTree to use those new methods.
Changed Page and Slice map(…) method to take a Function over a Converter so that act as specialization of the newly introduced map(…) method.
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.
Re added PropertyDescriptor collection. Looks like the method got dropped during one of the rebase operations.
Additionally make use of .distinct() name collection in tests as descriptors might appear multiple times for the same property name.
Javaslang's collection and map types can now be used on repository query methods and get adapted similarly to nullable wrapper types (like JDK's Optional). Also made TypeInformation infrastructure aware of the map type so that a value type lookup gets handle correctly.
RepositoryMetadata now exposes an ….isReactiveRepository() that's implemented by inspecting the backing repository interface for any reactive wrapper type appearing in method signatures. That allows us to move down the use of a ConversionService down to ReactiveRepositoryInformation.WrapperConversionMatch.
Made a couple of methods static that could be. Simplified some logic using streams. A bit better wording in assertions. Some formatting when using streams.
Previously, calls to ParameterizedTypeInformation.getMapValueType() caused an infinite recursion when invoked on a type information that was not a map type. This lead to a StackOverflowError.
We now call the super method doGetMapValueType() instead of calling the entry super method getMapValueType() and return by that null in case the map value type is not resolvable.
Original pull request: #176.
If the same generic type was used on recursively nested generics declarations, like this:
class GenericType<T> {}
class Nested extends GenericType<String> {}
class Concrete extends GenericType<Nested> {}
our traversal of the generics discovered T bound to String in Nested and as that is extending GenericType as well, the T detected here is the same instance as the T within the map discovered for Concrete. As we previously added the nested types after we added the original entry, the nested discovery overwrote the more local one.
We now make sure the detected nested type variable mappings don't overwrite already existing ones.
We now also cache a failed property lookup so that we can return null on a subsequent call for the same invalid property name right away and don't have to reattempt the lookup unnecessarily.
The translation of the list of actual type parameters into an array now uses the loop index correctly. Previously, it always used the first type parameter.
Added proper equals(…) and hashCode() methods to SyntheticParameterizedType to make sure instances created for the same type information and type parameters are considered equal.