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.
We now resolve composed annotation values using @AliasFor within AnnotationBasedPersistentProperty and BasicPersistentEntity. Nevertheless it is up to the individual store implementation to make use of this.
Original pull request: #156.
QueryMethods now expose a ResourceProcessor which is exposes information about the final to be created object types which can either be DTOs containing a persistence constructor (see @PersistenceConstructor) or projection interfaces. The former are analyzed for constructor properties so that store implementations can use that information to create projected queries that return exactly the fields required for that DTO.
Projection interfaces are inspected, their properties are considered input properties and the same projection queries can be issued against the data store. If a projection contains dynamically calculated properties (i.e. it uses SpEL expressions via @Value) the original entities have to be queried and can be projected during post processing.
ProjectionFactory now exposes a more advanced ProjectionInformation that has additional meta information about the projection type. ProxyProjectionFactory now refers to the BeanClassLoader instead of the ResourceLoader.
RepositoryFactory(Bean)Support now also implement BeanFactoryAware to forward the BeanFactory to the SpelAwareProxyProjectionFactory which in turn now gets handed into the QueryLookupStrategy as well as the QueryMethod.
Parameter now knows about a dynamic projection type, which is a query method parameter of type Class bound to a generic method parameter and will be used to determine the projection to be used on a per call basis.
Original pull request: #150.
If the type lookup from the store source returns a raw generic type (e.g. resolving the value of a generic property against a value of that generic type - i.e. not a more concrete type binding the generic information) in the context of a generic property, we previously did not apply the generics information of the contextual instance to that very raw type.
We now expose a TypeInformation.specialize(ClassTypeInformation) which applies the current generics context to the given raw type and basically creates a synthetic parameterized TypeInformation instance.
DefaultTypeMapper applies this specialization by default now with ClassTypeInformation simply returning the given type as is so that we don't create any resolution overhead in case no generics are involved in the first place.
Extended Version value object to correctly dump a non-numeric last segment of a version string to parse. Incorrect source version strings now raise an IllegalArgumentException better explaining the cause.
Related tickets: DATACMNS-496.
We now implement EnvironmentAware and ResourceLoaderAware to respect the current environment setup when scanning for types. We use the ResourceLoader's ClassLoader if configured but indicate to fall back to the default one if none configured.
In case we create a ParameterizedTypeInformation for a property we now also analyze the field-local generics information and add the discovered type mappings to the type variable map.
RepositoryFactorySupport now exposes a setRepositoryBaseClass(…) to take a custom type that instances will be created reflectively for. This removes the need for a boilerplate repository factory and FactoryBean implementation to hook custom repository base class implementations into the infrastructure.
RepositoryFactorySupport now exposes a getTargetRepositoryViaReflection(…) method to allow sub-classes to create repository instances and consider customized repository base classes nonetheless. getTargetRepository(…) needs a tiny signature change which unfortunately requires imple
Fixed schema registration for version 1.8 schema. Added new XSD containing a base-class attribute on the <repositories /> element to customize the repository base class via XML.
Removed outdated section of how to create a custom base repository class from the reference documentation and replaced it with new simplified instructions.
Deprecated usage of factory-class attribute in configuration. Point users to newly introduced way of configuring a base class directly to avoid the need for a boilerplate repository factory and factory bean implementation.
DefaultRepositoryInformation now makes target class methods assignable before caching and returning them, so that they can always be invoked reflectively. Made this aspect part of the contract of RepositoryInformation.getTargetClassMethod(…).
Primarily intended to be used with Distance instances, we introduce a Range value type. Distance now has factory methods to create Range instances between two distances. To support this, Distance now implements comparable based on the normalized value of it.
Tiny refactoring in TypeDiscoverer to avoid code duplication between the lookup of parameter type information for constructors and methods.
Added stream to the list of supported query method prefixes. Allow Stream to be used as return type for paginating queries, too.
Renamed Java8StreamUtils to StreamUtils. Some additional JavaDoc.
Original pull request: #116.
A CloseableIterator abstracts the underlying result with support for releasing the associated resources via close() which can be transparently be used with try-with-resources in Java 7 since Closeable implements AutoCloseable from Java 7 on upwards. Added detector methods to QueryMethod to check whether the current method returns a Stream.
Introduced ReflectionUtils.isJava8StreamType to safely detect whether the given type is assignable to a Java 8 Stream. Introduced CloseableIteratorDisposingRunnable that can be registered as a cleanup action on a Stream.
Original pull request: #116.
Made ObjectInstantiator interface public as otherwise the generated class to implement it cannot access it and thus the usage of the ByteCodeGeneratingEntityInstantiator fails completely.
PreferredConstructor.isEnclosingClassParameter(…) now eagerly returns if the parameter itself is not an enclosing one and thus avoids a collection lookup and equals check. Moved equals check for the type to the very end of the equals check to increase the chances that other inequality guards kick in earlier.
AbstractMappingContext now leaves the non-null-check for getPersistentEntity(…) to the factory method of ClassTypeInformation.
We now pre-calculate the hash codes for TypeInformation implementations as far as possible as the instances are used as cache keys quite a lot. The same applies to AbstractPersistentProperty.
BasicPersistentEntity now uses an ArrayList we sort during the verify() phase to mimic the previous behavior wich was implemented using a TreeSet as ArrayLists are way more performant when iterating over all elements which doWithProperties(…) is doing which is used quite a lot.
BeanWrapper now avoids the getter lookup if field access is used.
SimpleTypeHolder now uses a CopyOnWriteArrySet to leniently add types detected to be simple to the set of simple types to avoid ongoing checks against the inheritance hierarchy.
We now make the field detected by the callback accessible so that the value lookup doesn't fail for private fields. Added a few more unit tests to verify behavior.
The initial setup of the type variable map now unfolds the detected types in the map to make sure we detect all type variables present in the current scope.
Added caching of component and map value TypeInformation instances to avoid repeated creation.
So far, the lookup of the type variable map was preferring the type variable maps detected on parent types in nested structures. This caused the concrete type variables in nested types not being considered correctly which caused the type resolution to fall back to the generic bounds.
We now accumulate the type variable maps to avoid having to lookup a certain map in the nesting hierarchy. The core fix is in ParentTypeAwareTypeInformation's constructor and mergeMaps(…) respectively. Simplified the handling of type variable maps and made proper use of generics throughout the class hierarchy.
DefaultRepositoryInformation now excludes default methods from the query methods it detects. RepositoryFactorySupport adds a special MethodInterceptor to the proxy which handles the invocation of default methods.
Related tickets: DATACMNS-535.
The equals(…) and hashCode() methods of TypeVariableTypeInformation previously tried to evaluate the unresolved context of the type variable. This can cause issues in recursive type definitions as set up in the according test case. We now implement the methods based on the resolved type to makes sure we break the recursive lookup of PersistentEntity instances in AbstractMappingContext.
The erroneous lookup was actually caused by unresolved base types being added to the mapping context within the JPA project as the JPA meta-model also returns those types as managed types.
Related pull request: #84.
Version parsing failed when given version contained non-numeric parts (like 2.0.0-rc1). We now strip everything after the first non numeric part to create a logical version equivalent of the source String.
Original pull request: #81.
The default implementations of the TypeInformation Mapper interfaces now work with ClassTypeInformation where possible to express they only map raw types effectively.
Added TypeInformation.getRawTypeInformation() to easily turn whatever TypeInformation into the raw type representation. Changed ClassTypeInformation.from(…) to return ClassTypeInformations directly.
Previously, ParameterizedTypeInformation.hashCode() had been inconsistent to equals in case of a fully resolved parameterized type. This is now fixed by not including the parent reference in case a parameterized type is resolved completely.
Also, TypeDiscoverer.getActualType() does not return the component type for non-collection/non-maps anymore to make sure we don't accidentally unwrap parameterized types.
Added AnnotatedTypeScanner to easily scan for annotated types within a set of base packages. Picks up interfaces by default which had to be customized when using ClassPathScanningCanidateComponentProvider.
Added DirectFieldAccessFallbackBeanWrapper that will use direct field access for beans in case no accessor method can be found. This allows to easily implement bean property values through accessors first but using the field directly if the accessors aren't available.
Introduced AnnotationDetectionMethodCallback to easily find methods equipped with a given annotation.
Previously the map value type resolving algorithm checked the value type to be of type Map again to shortcut the resolution. We now weakened this to an assignment check and eagerly resolve the generic type if its bound on exactly that level already. If no concrete type argument can be found, we fall back to the general generics resolution mechanism.
In case of an unresolvable generic parameter in TypeDiscoverer's getTypeArgument(…) we check for a generic super type for the given bound and fall back to Object in case we find a parameterized type.
Suppress deprecation warnings for GenericTypeResolver for now. Added Simple(Property|Association)Handler to ease working with untyped PersistentProperty instances without having to fall back to raw types. Polished Sonargraph architecture description.
We're now rejecting invalid constructor arguments handed to ClassTypeInformation, Part, PartTree and PropertyPath. Beyond that we skip the creation of a Part for an empty path segment, so that you don't end up with an invalid Part instance for a findAllByOrderByFooAsc.
We now leniently try to lookup DefaultParameterNameDiscoverer and create an instance of it to make use of Spring 4's improved parameter name capabilities on Java 8. We fall back on a LocalVariableTableParameterNameDiscoverer if on Spring versions prior to 4.
Reverted from ConcurrentHashMap to plain HashMap where concurrency wasn't an issue and profiling showed performance hotspots. Introduced caches for ParameterizedTypeInformation.getComponentType() and the resolved raw type in TypeDiscoverer.
So far the property lookup of a nested property path (e.g. "foo.bar") failed in cases the head property was not cached already. We now recursively resolve the type information even for an unpopulated cache.