Polishing.
Move all primary interaction API into TypeInformation to prepare making all implementations package protected. Adapt all deprecated API usage in Spring Data Commons to the new one.
Benchmark results look as follows:
2.7
Mode Cnt Score Error Units
TypicalEntityReaderBenchmark.hasReadTarget thrpt 10 81982861,995 ± 269948,368 ops/s
TypicalEntityReaderBenchmark.kotlinDataClass thrpt 10 18472975,689 ± 161234,912 ops/s
TypicalEntityReaderBenchmark.kotlinDataClassWithDefaulting thrpt 10 4029631,568 ± 18990,863 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedConstructorAndField thrpt 10 11495517,933 ± 209269,454 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedConstructorAndProperty thrpt 10 11192152,036 ± 249721,563 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedConstructorArgsCreation thrpt 10 18835101,279 ± 81895,338 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedFieldAccess thrpt 10 16309896,939 ± 80376,406 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedPropertyAccess thrpt 10 15471691,537 ± 52426,121 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveConstructorAndField thrpt 10 12080159,283 ± 49922,326 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveConstructorAndProperty thrpt 10 12166160,066 ± 173876,051 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveConstructorArgsCreation thrpt 10 13548906,437 ± 485944,886 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveFieldAccess thrpt 10 16457347,670 ± 64170,567 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectivePropertyAccess thrpt 10 14115878,948 ± 57491,268 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectivePropertyAccessWithCustomConversionRegistry thrpt 10 15137904,257 ± 51148,726 ops/s
DefaultTypeMapperBenchmark.readTyped thrpt 10 146820080,682 ± 13254238,407 ops/s
DefaultTypeMapperBenchmark.readTypedWithBaseType thrpt 10 55420351,827 ± 1888634,217 ops/s
DefaultTypeMapperBenchmark.readUntyped thrpt 10 193934847,273 ± 442867,276 ops/s
DefaultTypeMapperBenchmark.readUntypedWithBaseType thrpt 10 192032977,366 ± 4300192,665 ops/s
3.0 – Before this change
Mode Cnt Score Error Units
TypicalEntityReaderBenchmark.hasReadTarget thrpt 10 81124249,138 ± 174095,495 ops/s
TypicalEntityReaderBenchmark.kotlinDataClass thrpt 10 18685936,220 ± 243939,063 ops/s
TypicalEntityReaderBenchmark.kotlinDataClassWithDefaulting thrpt 10 4125709,048 ± 17615,890 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedConstructorAndField thrpt 10 12277837,989 ± 96973,908 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedConstructorAndProperty thrpt 10 12419978,391 ± 45780,658 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedConstructorArgsCreation thrpt 10 18744593,010 ± 71655,735 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedFieldAccess thrpt 10 16497286,465 ± 41150,718 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedPropertyAccess thrpt 10 15639640,554 ± 69758,391 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveConstructorAndField thrpt 10 11715068,503 ± 66085,900 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveConstructorAndProperty thrpt 10 12159285,083 ± 58171,950 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveConstructorArgsCreation thrpt 10 13711647,512 ± 66496,271 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveFieldAccess thrpt 10 16287057,838 ± 54826,532 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectivePropertyAccess thrpt 10 13847665,634 ± 127834,292 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectivePropertyAccessWithCustomConversionRegistry thrpt 10 15099300,270 ± 89030,403 ops/s
DefaultTypeMapperBenchmark.readTyped thrpt 10 151893972,774 ± 494555,250 ops/s
DefaultTypeMapperBenchmark.readTypedWithBaseType thrpt 10 55869432,892 ± 389099,409 ops/s
DefaultTypeMapperBenchmark.readUntyped thrpt 10 192661151,755 ± 1075079,924 ops/s
DefaultTypeMapperBenchmark.readUntypedWithBaseType thrpt 10 192315554,269 ± 3061160,314 ops/s
3.0 – After this change
Mode Cnt Score Error Units
TypicalEntityReaderBenchmark.hasReadTarget thrpt 10 82650245,236 ± 321384,577 ops/s
TypicalEntityReaderBenchmark.kotlinDataClass thrpt 10 21304680,430 ± 396764,834 ops/s
TypicalEntityReaderBenchmark.kotlinDataClassWithDefaulting thrpt 10 4422187,275 ± 35088,721 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedConstructorAndField thrpt 10 13345503,496 ± 180490,423 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedConstructorAndProperty thrpt 10 13911653,366 ± 266028,886 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedConstructorArgsCreation thrpt 10 21192316,261 ± 356534,938 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedFieldAccess thrpt 10 17533419,173 ± 49226,408 ops/s
TypicalEntityReaderBenchmark.simpleEntityGeneratedPropertyAccess thrpt 10 17393382,078 ± 114774,442 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveConstructorAndField thrpt 10 12867285,952 ± 62870,980 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveConstructorAndProperty thrpt 10 13208453,130 ± 272795,070 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveConstructorArgsCreation thrpt 10 14998467,714 ± 84265,782 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectiveFieldAccess thrpt 10 17365982,413 ± 115287,403 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectivePropertyAccess thrpt 10 15503841,949 ± 123631,592 ops/s
TypicalEntityReaderBenchmark.simpleEntityReflectivePropertyAccessWithCustomConversionRegistry thrpt 10 15716685,449 ± 64686,646 ops/s
DefaultTypeMapperBenchmark.readTyped thrpt 10 154433835,941 ± 1391455,835 ops/s
DefaultTypeMapperBenchmark.readTypedWithBaseType thrpt 10 77919886,633 ± 438244,738 ops/s
DefaultTypeMapperBenchmark.readUntyped thrpt 10 194435210,217 ± 936274,571 ops/s
DefaultTypeMapperBenchmark.readUntypedWithBaseType thrpt 10 193768718,043 ± 475103,167 ops/s
Original pull request: #2572.
Related ticket: #2312.
This commit is contained in:
@@ -22,7 +22,6 @@ import java.util.Map.Entry;
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -37,8 +36,8 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class ConfigurableTypeInformationMapper implements TypeInformationMapper {
|
||||
|
||||
private final Map<ClassTypeInformation<?>, Alias> typeToAlias;
|
||||
private final Map<Alias, ClassTypeInformation<?>> aliasToType;
|
||||
private final Map<TypeInformation<?>, Alias> typeToAlias;
|
||||
private final Map<Alias, TypeInformation<?>> aliasToType;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ConfigurableTypeInformationMapper} for the given type map.
|
||||
@@ -54,7 +53,7 @@ public class ConfigurableTypeInformationMapper implements TypeInformationMapper
|
||||
|
||||
for (Entry<? extends Class<?>, String> entry : sourceTypeMap.entrySet()) {
|
||||
|
||||
ClassTypeInformation<?> type = ClassTypeInformation.from(entry.getKey());
|
||||
TypeInformation<?> type = TypeInformation.of(entry.getKey());
|
||||
Alias alias = Alias.of(entry.getValue());
|
||||
|
||||
if (typeToAlias.containsValue(alias)) {
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -149,16 +148,16 @@ public class DefaultTypeMapper<S> implements TypeMapper<S>, BeanClassLoaderAware
|
||||
|
||||
Class<T> rawType = basicType.getType();
|
||||
|
||||
boolean isMoreConcreteCustomType = rawType == null
|
||||
|| rawType.isAssignableFrom(documentsTargetType) && !rawType.equals(documentsTargetType);
|
||||
boolean isMoreConcreteCustomType = (rawType == null)
|
||||
|| (rawType.isAssignableFrom(documentsTargetType) && !rawType.equals(documentsTargetType));
|
||||
|
||||
if (!isMoreConcreteCustomType) {
|
||||
return basicType;
|
||||
}
|
||||
|
||||
ClassTypeInformation<?> targetType = ClassTypeInformation.from(documentsTargetType);
|
||||
TypeInformation<?> targetType = TypeInformation.of(documentsTargetType);
|
||||
|
||||
return (TypeInformation<? extends T>) basicType.specialize(targetType);
|
||||
return basicType.specialize(targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,7 +189,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S>, BeanClassLoaderAware
|
||||
|
||||
@Override
|
||||
public void writeType(Class<?> type, S dbObject) {
|
||||
writeType(ClassTypeInformation.from(type), dbObject);
|
||||
writeType(TypeInformation.of(type), dbObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -36,7 +35,7 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
public class SimpleTypeInformationMapper implements TypeInformationMapper, BeanClassLoaderAware {
|
||||
|
||||
private final Map<String, Optional<ClassTypeInformation<?>>> cache = new ConcurrentHashMap<>();
|
||||
private final Map<String, Optional<TypeInformation<?>>> cache = new ConcurrentHashMap<>();
|
||||
|
||||
private @Nullable ClassLoader classLoader;
|
||||
|
||||
@@ -79,10 +78,10 @@ public class SimpleTypeInformationMapper implements TypeInformationMapper, BeanC
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
private Optional<ClassTypeInformation<?>> loadClass(String typeName) {
|
||||
private Optional<TypeInformation<?>> loadClass(String typeName) {
|
||||
|
||||
try {
|
||||
return Optional.of(ClassTypeInformation.from(ClassUtils.forName(typeName, this.classLoader)));
|
||||
return Optional.of(TypeInformation.of(ClassUtils.forName(typeName, this.classLoader)));
|
||||
} catch (ClassNotFoundException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public interface ValueConversionContext<P extends PersistentProperty<P>> {
|
||||
*/
|
||||
@Nullable
|
||||
default <T> T write(@Nullable Object value, @NonNull Class<T> target) {
|
||||
return write(value, ClassTypeInformation.from(target));
|
||||
return write(value, TypeInformation.of(target));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +119,7 @@ public interface ValueConversionContext<P extends PersistentProperty<P>> {
|
||||
*/
|
||||
@Nullable
|
||||
default <T> T read(@Nullable Object value, @NonNull Class<T> target) {
|
||||
return read(value, ClassTypeInformation.from(target));
|
||||
return read(value, TypeInformation.of(target));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -68,7 +68,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
* @param owningType must not be {@literal null}.
|
||||
*/
|
||||
PropertyPath(String name, Class<?> owningType) {
|
||||
this(name, ClassTypeInformation.from(owningType), Collections.emptyList());
|
||||
this(name, TypeInformation.of(owningType), Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,7 +315,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
* @return
|
||||
*/
|
||||
public static PropertyPath from(String source, Class<?> type) {
|
||||
return from(source, ClassTypeInformation.from(type));
|
||||
return from(source, TypeInformation.of(type));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -189,7 +189,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
|
||||
@Nullable
|
||||
public E getPersistentEntity(Class<?> type) {
|
||||
return getPersistentEntity(ClassTypeInformation.from(type));
|
||||
return getPersistentEntity(TypeInformation.of(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,7 +197,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
TypeInformation<?> typeInformation = ClassTypeInformation.from(type);
|
||||
TypeInformation<?> typeInformation = TypeInformation.of(type);
|
||||
|
||||
try {
|
||||
|
||||
@@ -312,7 +312,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
*/
|
||||
protected final <T> PersistentPropertyPaths<T, P> doFindPersistentPropertyPaths(Class<T> type,
|
||||
Predicate<? super P> predicate, Predicate<P> traversalGuard) {
|
||||
return persistentPropertyPathFactory.from(ClassTypeInformation.from(type), predicate, traversalGuard);
|
||||
return persistentPropertyPathFactory.from(TypeInformation.of(type), predicate, traversalGuard);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -322,7 +322,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* @return
|
||||
*/
|
||||
protected Optional<E> addPersistentEntity(Class<?> type) {
|
||||
return addPersistentEntity(ClassTypeInformation.from(type));
|
||||
return addPersistentEntity(TypeInformation.of(type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -728,7 +728,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
*/
|
||||
public PropertyMatch(@Nullable String namePattern, @Nullable String typeName) {
|
||||
|
||||
Assert.isTrue(!(namePattern == null && typeName == null), "Either name pattern or type name must be given");
|
||||
Assert.isTrue(!((namePattern == null) && (typeName == null)), "Either name pattern or type name must be given");
|
||||
|
||||
this.namePattern = namePattern;
|
||||
this.typeName = typeName;
|
||||
@@ -746,11 +746,11 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
Assert.notNull(name, "Name must not be null");
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
if (namePattern != null && !name.matches(namePattern)) {
|
||||
if ((namePattern != null) && !name.matches(namePattern)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeName != null && !type.getName().equals(typeName)) {
|
||||
if ((typeName != null) && !type.getName().equals(typeName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class PersistentPropertyPathFactory<E extends PersistentEntity<?, P>, P extends
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
Assert.notNull(propertyPath, "Property path must not be null");
|
||||
|
||||
return getPersistentPropertyPath(ClassTypeInformation.from(type), propertyPath);
|
||||
return getPersistentPropertyPath(TypeInformation.of(type), propertyPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +112,7 @@ class PersistentPropertyPathFactory<E extends PersistentEntity<?, P>, P extends
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
Assert.notNull(propertyFilter, "Property filter must not be null");
|
||||
|
||||
return from(ClassTypeInformation.from(type), propertyFilter);
|
||||
return from(TypeInformation.of(type), propertyFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,7 +131,7 @@ class PersistentPropertyPathFactory<E extends PersistentEntity<?, P>, P extends
|
||||
Assert.notNull(propertyFilter, "Property filter must not be null");
|
||||
Assert.notNull(traversalGuard, "Traversal guard must not be null");
|
||||
|
||||
return from(ClassTypeInformation.from(type), propertyFilter, traversalGuard);
|
||||
return from(TypeInformation.of(type), propertyFilter, traversalGuard);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -88,7 +88,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
return Optional.of(Reference.class) //
|
||||
.map(this::findAnnotation) //
|
||||
.map(Reference::to) //
|
||||
.map(it -> !Class.class.equals(it) ? ClassTypeInformation.from(it) : getActualTypeInformation()) //
|
||||
.map(it -> !Class.class.equals(it) ? TypeInformation.of(it) : getActualTypeInformation()) //
|
||||
.orElseGet(() -> super.getAssociationTargetTypeInformation());
|
||||
});
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public interface PreferredConstructorDiscoverer<T, P extends PersistentProperty<
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
return Discoverers.findDiscoverer(type) //
|
||||
.discover(ClassTypeInformation.from(type), null);
|
||||
.discover(TypeInformation.of(type), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -37,6 +36,7 @@ import org.springframework.lang.Nullable;
|
||||
* @param <D> the domain type.
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Drotbohm
|
||||
* @since 2.7
|
||||
*/
|
||||
public class EntityProjection<M, D> implements Streamable<EntityProjection.PropertyProjection<?, ?>> {
|
||||
@@ -90,7 +90,9 @@ public class EntityProjection<M, D> implements Streamable<EntityProjection.Prope
|
||||
* @return new instance of {@link EntityProjection}.
|
||||
*/
|
||||
public static <T> EntityProjection<T, T> nonProjecting(Class<T> type) {
|
||||
ClassTypeInformation<T> typeInformation = ClassTypeInformation.from(type);
|
||||
|
||||
TypeInformation<T> typeInformation = TypeInformation.of(type);
|
||||
|
||||
return new EntityProjection<>(typeInformation, typeInformation, Collections.emptyList(), false,
|
||||
ProjectionType.CLOSED);
|
||||
}
|
||||
|
||||
@@ -25,9 +25,8 @@ import java.util.Set;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.projection.EntityProjection.ProjectionType;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.projection.EntityProjection.ProjectionType;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -39,6 +38,7 @@ import org.springframework.util.Assert;
|
||||
* @author Gerrit Meier
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Drotbohm
|
||||
* @since 2.7
|
||||
*/
|
||||
public class EntityProjectionIntrospector {
|
||||
@@ -91,8 +91,8 @@ public class EntityProjectionIntrospector {
|
||||
*/
|
||||
public <M, D> EntityProjection<M, D> introspect(Class<M> mappedType, Class<D> domainType) {
|
||||
|
||||
ClassTypeInformation<M> returnedTypeInformation = ClassTypeInformation.from(mappedType);
|
||||
ClassTypeInformation<D> domainTypeInformation = ClassTypeInformation.from(domainType);
|
||||
TypeInformation<M> returnedTypeInformation = TypeInformation.of(mappedType);
|
||||
TypeInformation<D> domainTypeInformation = TypeInformation.of(domainType);
|
||||
|
||||
boolean isProjection = projectionPredicate.test(mappedType, domainType);
|
||||
|
||||
@@ -111,7 +111,8 @@ public class EntityProjectionIntrospector {
|
||||
List<EntityProjection.PropertyProjection<?, ?>> propertyDescriptors = getProperties(null, projectionInformation,
|
||||
returnedTypeInformation, persistentEntity, null);
|
||||
|
||||
return EntityProjection.projecting(returnedTypeInformation, domainTypeInformation, propertyDescriptors, ProjectionType.CLOSED);
|
||||
return EntityProjection.projecting(returnedTypeInformation, domainTypeInformation, propertyDescriptors,
|
||||
ProjectionType.CLOSED);
|
||||
}
|
||||
|
||||
private List<EntityProjection.PropertyProjection<?, ?>> getProperties(@Nullable PropertyPath propertyPath,
|
||||
@@ -157,10 +158,12 @@ public class EntityProjectionIntrospector {
|
||||
|
||||
if (container) {
|
||||
propertyDescriptors.add(EntityProjection.ContainerPropertyProjection.projecting(nestedPropertyPath, property,
|
||||
persistentProperty.getTypeInformation(), nestedPropertyDescriptors, ProjectionType.from(projectionInformation)));
|
||||
persistentProperty.getTypeInformation(), nestedPropertyDescriptors,
|
||||
ProjectionType.from(projectionInformation)));
|
||||
} else {
|
||||
propertyDescriptors.add(EntityProjection.PropertyProjection.projecting(nestedPropertyPath, property,
|
||||
persistentProperty.getTypeInformation(), nestedPropertyDescriptors, ProjectionType.from(projectionInformation)));
|
||||
persistentProperty.getTypeInformation(), nestedPropertyDescriptors,
|
||||
ProjectionType.from(projectionInformation)));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -25,10 +25,8 @@ import java.util.Map.Entry;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.NullableWrapper;
|
||||
import org.springframework.data.util.NullableWrapperConverters;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -66,7 +64,7 @@ class ProjectingMethodInterceptor implements MethodInterceptor {
|
||||
@Override
|
||||
public Object invoke(@SuppressWarnings("null") @NonNull MethodInvocation invocation) throws Throwable {
|
||||
|
||||
TypeInformation<?> type = ClassTypeInformation.fromReturnTypeOf(invocation.getMethod());
|
||||
TypeInformation<?> type = TypeInformation.fromReturnTypeOf(invocation.getMethod());
|
||||
TypeInformation<?> resultType = type;
|
||||
TypeInformation<?> typeToReturn = type;
|
||||
|
||||
@@ -74,7 +72,7 @@ class ProjectingMethodInterceptor implements MethodInterceptor {
|
||||
boolean applyWrapper = false;
|
||||
|
||||
if (NullableWrapperConverters.supports(type.getType())
|
||||
&& (result == null || !NullableWrapperConverters.supports(result.getClass()))) {
|
||||
&& ((result == null) || !NullableWrapperConverters.supports(result.getClass()))) {
|
||||
resultType = NullableWrapperConverters.unwrapActualType(typeToReturn);
|
||||
applyWrapper = true;
|
||||
}
|
||||
@@ -161,7 +159,7 @@ class ProjectingMethodInterceptor implements MethodInterceptor {
|
||||
|
||||
@Nullable
|
||||
private Object getProjection(@Nullable Object result, Class<?> returnType) {
|
||||
return result == null || ClassUtils.isAssignable(returnType, result.getClass()) ? result
|
||||
return (result == null) || ClassUtils.isAssignable(returnType, result.getClass()) ? result
|
||||
: factory.createProjection(returnType, result);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.mapping.PropertyReferenceException;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -175,7 +174,7 @@ public class QuerydslBindings {
|
||||
Assert.notNull(path, "Path must not be null");
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
return isPathAvailable(path, ClassTypeInformation.from(type));
|
||||
return isPathAvailable(path, TypeInformation.of(type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -573,7 +572,7 @@ public class QuerydslBindings {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
@@ -589,7 +588,7 @@ public class QuerydslBindings {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = ObjectUtils.nullSafeHashCode(path);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(binding);
|
||||
result = (31 * result) + ObjectUtils.nullSafeHashCode(binding);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.util.QueryExecutionConverters;
|
||||
import org.springframework.data.repository.util.ReactiveWrapperConverters;
|
||||
import org.springframework.data.repository.util.ReactiveWrappers;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.KotlinReflectionUtils;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -60,7 +59,7 @@ public abstract class AbstractRepositoryMetadata implements RepositoryMetadata {
|
||||
Assert.isTrue(repositoryInterface.isInterface(), "Given type must be an interface");
|
||||
|
||||
this.repositoryInterface = repositoryInterface;
|
||||
this.typeInformation = ClassTypeInformation.from(repositoryInterface);
|
||||
this.typeInformation = TypeInformation.of(repositoryInterface);
|
||||
this.crudMethods = Lazy.of(() -> new DefaultCrudMethods(this));
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.util.function.Function;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.repository.RepositoryDefinition;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -78,6 +77,6 @@ public class AnnotationRepositoryMetadata extends AbstractRepositoryMetadata {
|
||||
throw new IllegalArgumentException(String.format("Could not resolve domain type of %s", repositoryInterface));
|
||||
}
|
||||
|
||||
return ClassTypeInformation.from(extractor.apply(annotation));
|
||||
return TypeInformation.of(extractor.apply(annotation));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -50,7 +49,7 @@ public class DefaultRepositoryMetadata extends AbstractRepositoryMetadata {
|
||||
super(repositoryInterface);
|
||||
Assert.isTrue(Repository.class.isAssignableFrom(repositoryInterface), MUST_BE_A_REPOSITORY);
|
||||
|
||||
List<TypeInformation<?>> arguments = ClassTypeInformation.from(repositoryInterface)//
|
||||
List<TypeInformation<?>> arguments = TypeInformation.of(repositoryInterface)//
|
||||
.getRequiredSuperTypeInformation(Repository.class)//
|
||||
.getTypeArguments();
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.Map;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
@@ -85,7 +84,7 @@ public class MethodInvocationValidator implements MethodInterceptor {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arguments.length < i || arguments[i] == null) {
|
||||
if ((arguments.length < i) || (arguments[i] == null)) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Parameter %s in %s.%s must not be null", nullability.getMethodParameterName(i),
|
||||
ClassUtils.getShortName(method.getDeclaringClass()), method.getName()));
|
||||
@@ -94,7 +93,7 @@ public class MethodInvocationValidator implements MethodInterceptor {
|
||||
|
||||
Object result = invocation.proceed();
|
||||
|
||||
if (result == null && !nullability.isNullableReturn()) {
|
||||
if ((result == null) && !nullability.isNullableReturn()) {
|
||||
throw new EmptyResultDataAccessException("Result must not be null", 1);
|
||||
}
|
||||
|
||||
@@ -170,7 +169,7 @@ public class MethodInvocationValidator implements MethodInterceptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
public boolean equals(@Nullable Object o) {
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
@@ -194,8 +193,8 @@ public class MethodInvocationValidator implements MethodInterceptor {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (nullableReturn ? 1 : 0);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(nullableParameters);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(methodParameters);
|
||||
result = (31 * result) + ObjectUtils.nullSafeHashCode(nullableParameters);
|
||||
result = (31 * result) + ObjectUtils.nullSafeHashCode(methodParameters);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.function.BiPredicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -75,8 +76,7 @@ public interface MethodLookup {
|
||||
/**
|
||||
* Value object representing an invoked {@link Method}.
|
||||
*/
|
||||
final
|
||||
class InvokedMethod {
|
||||
final class InvokedMethod {
|
||||
|
||||
private final Method method;
|
||||
|
||||
@@ -109,7 +109,7 @@ public interface MethodLookup {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
public boolean equals(@Nullable Object o) {
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.data.repository.core.support.MethodLookup.MethodPredi
|
||||
import org.springframework.data.repository.util.QueryExecutionConverters;
|
||||
import org.springframework.data.repository.util.ReactiveWrapperConverters;
|
||||
import org.springframework.data.repository.util.ReactiveWrappers;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -58,7 +59,7 @@ interface MethodLookups {
|
||||
static MethodLookup direct() {
|
||||
|
||||
MethodPredicate direct = (MethodPredicate) (invoked, candidate) -> candidate.getName().equals(invoked.getName())
|
||||
&& candidate.getParameterCount() == invoked.getParameterCount()
|
||||
&& (candidate.getParameterCount() == invoked.getParameterCount())
|
||||
&& Arrays.equals(candidate.getParameterTypes(), invoked.getParameterTypes());
|
||||
|
||||
return () -> Collections.singletonList(direct);
|
||||
@@ -248,8 +249,8 @@ interface MethodLookups {
|
||||
|
||||
MethodPredicate detailedComparison = (MethodPredicate) (invokedMethod,
|
||||
candidate) -> getMethodCandidate(invokedMethod,
|
||||
candidate,
|
||||
matchParameterOrComponentType(repositoryMetadata.getRepositoryInterface())).isPresent();
|
||||
candidate,
|
||||
matchParameterOrComponentType(repositoryMetadata.getRepositoryInterface())).isPresent();
|
||||
|
||||
return Arrays.asList(convertibleComparison, detailedComparison);
|
||||
}
|
||||
@@ -434,7 +435,7 @@ interface MethodLookups {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
public boolean equals(@Nullable Object o) {
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
@@ -454,7 +455,7 @@ interface MethodLookups {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = ObjectUtils.nullSafeHashCode(declared);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(base);
|
||||
result = (31 * result) + ObjectUtils.nullSafeHashCode(base);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ public class RepositoryComposition {
|
||||
|
||||
Class<?> parameterType = parameterTypes.length > i ? parameterTypes[i] : null;
|
||||
|
||||
if (value != null && parameterType != null) {
|
||||
if ((value != null) && (parameterType != null)) {
|
||||
if (!parameterType.isAssignableFrom(value.getClass())
|
||||
&& ReactiveWrapperConverters.canConvert(value.getClass(), parameterType)) {
|
||||
|
||||
@@ -558,7 +558,7 @@ public class RepositoryComposition {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
public boolean equals(@Nullable Object o) {
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
@@ -582,8 +582,8 @@ public class RepositoryComposition {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = ObjectUtils.nullSafeHashCode(fragmentCache);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(invocationMetadataCache);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(fragments);
|
||||
result = (31 * result) + ObjectUtils.nullSafeHashCode(invocationMetadataCache);
|
||||
result = (31 * result) + ObjectUtils.nullSafeHashCode(fragments);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.data.repository.query;
|
||||
|
||||
import static java.lang.String.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -32,10 +31,8 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.util.ClassUtils;
|
||||
import org.springframework.data.repository.util.QueryExecutionConverters;
|
||||
import org.springframework.data.repository.util.ReactiveWrapperConverters;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.data.util.TypeDiscoverer;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -218,7 +215,9 @@ public class Parameter {
|
||||
}
|
||||
|
||||
ResolvableType returnType = ResolvableType.forMethodReturnType(parameter.getMethod());
|
||||
if(new TypeDiscoverer(returnType).isCollectionLike() || org.springframework.util.ClassUtils.isAssignable(Stream.class, returnType.toClass())) {
|
||||
|
||||
if (TypeInformation.of(returnType).isCollectionLike()
|
||||
|| org.springframework.util.ClassUtils.isAssignable(Stream.class, returnType.toClass())) {
|
||||
returnType = returnType.getGeneric(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ import org.springframework.data.repository.core.EntityMetadata;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.util.QueryExecutionConverters;
|
||||
import org.springframework.data.repository.util.ReactiveWrapperConverters;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -108,7 +107,7 @@ public class QueryMethod {
|
||||
Class<?> repositoryDomainClass = metadata.getDomainType();
|
||||
Class<?> methodDomainClass = metadata.getReturnedDomainClass(method);
|
||||
|
||||
return repositoryDomainClass == null || repositoryDomainClass.isAssignableFrom(methodDomainClass)
|
||||
return (repositoryDomainClass == null) || repositoryDomainClass.isAssignableFrom(methodDomainClass)
|
||||
? methodDomainClass
|
||||
: repositoryDomainClass;
|
||||
});
|
||||
@@ -271,7 +270,7 @@ public class QueryMethod {
|
||||
return !QueryExecutionConverters.isSingleValue(unwrappedReturnType);
|
||||
}
|
||||
|
||||
return ClassTypeInformation.from(unwrappedReturnType).isCollectionLike();
|
||||
return TypeInformation.of(unwrappedReturnType).isCollectionLike();
|
||||
}
|
||||
|
||||
private static Class<? extends Object> potentiallyUnwrapReturnTypeFor(RepositoryMetadata metadata, Method method) {
|
||||
@@ -301,7 +300,7 @@ public class QueryMethod {
|
||||
Assert.notEmpty(types, "Types must not be null or empty");
|
||||
|
||||
// TODO: to resolve generics fully we'd need the actual repository interface here
|
||||
TypeInformation<?> returnType = ClassTypeInformation.fromReturnTypeOf(method);
|
||||
TypeInformation<?> returnType = TypeInformation.fromReturnTypeOf(method);
|
||||
|
||||
returnType = QueryExecutionConverters.isSingleValue(returnType.getType()) //
|
||||
? returnType.getRequiredComponentType() //
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -114,13 +113,13 @@ public abstract class ClassUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of occurrences for the given {@link Method#getParameterTypes() parameter type}
|
||||
* in the given {@link Method}.
|
||||
* Returns the number of occurrences for the given {@link Method#getParameterTypes() parameter type} in the given
|
||||
* {@link Method}.
|
||||
*
|
||||
* @param method {@link Method} to evaluate.
|
||||
* @param parameterType {@link Class} of the {@link Method} parameter type to count.
|
||||
* @return the number of occurrences for the given {@link Method#getParameterTypes() parameter type}
|
||||
* in the given {@link Method}.
|
||||
* @return the number of occurrences for the given {@link Method#getParameterTypes() parameter type} in the given
|
||||
* {@link Method}.
|
||||
* @see java.lang.reflect.Method#getParameterTypes()
|
||||
*/
|
||||
public static int getNumberOfOccurrences(@NonNull Method method, @NonNull Class<?> parameterType) {
|
||||
@@ -195,9 +194,11 @@ public abstract class ClassUtils {
|
||||
// TODO: we should also consider having the owning type here so we can resolve generics better.
|
||||
private static TypeInformation<?> getEffectivelyReturnedTypeFrom(Method method) {
|
||||
|
||||
TypeInformation<?> returnType = ClassTypeInformation.fromReturnTypeOf(method);
|
||||
return QueryExecutionConverters.supports(returnType.getType())
|
||||
|| ReactiveWrapperConverters.supports(returnType.getType()) ? returnType.getRequiredComponentType()
|
||||
TypeInformation<?> returnType = TypeInformation.fromReturnTypeOf(method);
|
||||
|
||||
return QueryExecutionConverters.supports(returnType.getType()) //
|
||||
|| ReactiveWrapperConverters.supports(returnType.getType()) //
|
||||
? returnType.getRequiredComponentType() //
|
||||
: returnType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,45 +16,85 @@
|
||||
package org.springframework.data.util;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;
|
||||
import org.springframework.util.ConcurrentLruCache;
|
||||
|
||||
/**
|
||||
* {@link TypeInformation} for a plain {@link Class}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @deprecated since 3.0 to go package protected at some point. Refer to {@link TypeInformation} only.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
|
||||
|
||||
public static final ClassTypeInformation<Collection> COLLECTION = new ClassTypeInformation(Collection.class);
|
||||
public static final ClassTypeInformation<List> LIST = new ClassTypeInformation(List.class);
|
||||
public static final ClassTypeInformation<Set> SET = new ClassTypeInformation(Set.class);
|
||||
public static final ClassTypeInformation<Map> MAP = new ClassTypeInformation(Map.class);
|
||||
public static final ClassTypeInformation<Object> OBJECT = new ClassTypeInformation(Object.class);
|
||||
private static final ConcurrentLruCache<ResolvableType, ClassTypeInformation<?>> cache = new ConcurrentLruCache<>(64,
|
||||
ClassTypeInformation::new);
|
||||
|
||||
private static final Map<Class<?>, ClassTypeInformation<?>> cache = new ConcurrentReferenceHashMap<>(64,
|
||||
ReferenceType.WEAK);
|
||||
@Deprecated public static final ClassTypeInformation<Collection> COLLECTION;
|
||||
@Deprecated public static final ClassTypeInformation<List> LIST;
|
||||
@Deprecated public static final ClassTypeInformation<Set> SET;
|
||||
@Deprecated public static final ClassTypeInformation<Map> MAP;
|
||||
@Deprecated public static final ClassTypeInformation<Object> OBJECT;
|
||||
|
||||
static {
|
||||
|
||||
OBJECT = (ClassTypeInformation<Object>) cache.get(ResolvableType.forClass(Object.class));
|
||||
COLLECTION = (ClassTypeInformation<Collection>) cache.get(ResolvableType.forClass(Collection.class));
|
||||
LIST = (ClassTypeInformation<List>) cache.get(ResolvableType.forClass(List.class));
|
||||
SET = (ClassTypeInformation<Set>) cache.get(ResolvableType.forClass(Set.class));
|
||||
MAP = (ClassTypeInformation<Map>) cache.get(ResolvableType.forClass(Map.class));
|
||||
}
|
||||
|
||||
private final Class<S> type;
|
||||
|
||||
ClassTypeInformation(ResolvableType type) {
|
||||
super(type);
|
||||
this.type = (Class<S>) type.resolve(Object.class);
|
||||
}
|
||||
|
||||
private ClassTypeInformation(Class<S> type) {
|
||||
super(ResolvableType.forClass(type));
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <S>
|
||||
* @param type
|
||||
* @return
|
||||
* @deprecated since 3.0. Use {@link TypeInformation#of} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <S> ClassTypeInformation<S> from(Class<S> type) {
|
||||
return cti(ResolvableType.forClass(type));
|
||||
}
|
||||
|
||||
static <S> ClassTypeInformation<S> cti(ResolvableType type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
return (ClassTypeInformation<S>) cache.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning: Does not fully resolve generic arguments.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
* @deprecated since 3.0 Use {@link #fromReturnTypeOf(Method, Class)} instead.
|
||||
* @deprecated since 3.0. Use {@link TypeInformation#fromReturnTypeOf(Method)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static TypeInformation<?> fromReturnTypeOf(Method method) {
|
||||
return new TypeDiscoverer<>(ResolvableType.forMethodReturnType(method));
|
||||
public static <S> TypeInformation<S> fromReturnTypeOf(Method method) {
|
||||
return (TypeInformation<S>) TypeInformation.of(ResolvableType.forMethodReturnType(method));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,35 +102,18 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
|
||||
* @param actualType can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static TypeInformation<?> fromReturnTypeOf(Method method, @Nullable Class<?> actualType) {
|
||||
static TypeInformation<?> fromReturnTypeOf(Method method, @Nullable Class<?> actualType) {
|
||||
|
||||
if(actualType == null) {
|
||||
return new TypeDiscoverer<>(ResolvableType.forMethodReturnType(method));
|
||||
}
|
||||
return new TypeDiscoverer<>(ResolvableType.forMethodReturnType(method, actualType));
|
||||
}
|
||||
var type = actualType == null
|
||||
? ResolvableType.forMethodReturnType(method)
|
||||
: ResolvableType.forMethodReturnType(method, actualType);
|
||||
|
||||
Class<?> type;
|
||||
|
||||
static {
|
||||
Arrays.asList(COLLECTION, LIST, SET, MAP, OBJECT).forEach(it -> cache.put(it.getType(), it));
|
||||
}
|
||||
|
||||
public static <S> ClassTypeInformation<S> from(Class<S> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
return (ClassTypeInformation<S>) cache.computeIfAbsent(type, ClassTypeInformation::new);
|
||||
}
|
||||
|
||||
ClassTypeInformation(Class<S> type) {
|
||||
super(ResolvableType.forClass(type));
|
||||
this.type = type;
|
||||
return TypeInformation.of(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<S> getType() {
|
||||
return (Class<S>) type;
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,7 +127,7 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeInformation<? extends S> specialize(ClassTypeInformation<?> type) {
|
||||
public TypeInformation<? extends S> specialize(TypeInformation<?> type) {
|
||||
return (TypeInformation<? extends S>) type;
|
||||
}
|
||||
|
||||
@@ -112,9 +135,4 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
|
||||
public String toString() {
|
||||
return type.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return super.equals(o);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,9 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -37,6 +35,7 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ConcurrentLruCache;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
@@ -49,55 +48,36 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @author Jürgen Diez
|
||||
* @author Alessandro Nistico
|
||||
* @author Johannes Englmeier
|
||||
* @deprecated since 3.0 to go package protected at some point. Prefer to refer to {@link TypeInformation} instead.
|
||||
*/
|
||||
public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
@Deprecated
|
||||
class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
protected static final Class<?>[] MAP_TYPES;
|
||||
private static final Class<?>[] COLLECTION_TYPES;
|
||||
|
||||
static {
|
||||
|
||||
var classLoader = TypeDiscoverer.class.getClassLoader();
|
||||
|
||||
Set<Class<?>> mapTypes = new HashSet<>();
|
||||
mapTypes.add(Map.class);
|
||||
|
||||
try {
|
||||
mapTypes.add(ClassUtils.forName("io.vavr.collection.Map", classLoader));
|
||||
} catch (ClassNotFoundException o_O) {}
|
||||
|
||||
MAP_TYPES = mapTypes.toArray(new Class[0]);
|
||||
|
||||
Set<Class<?>> collectionTypes = new HashSet<>();
|
||||
collectionTypes.add(Collection.class);
|
||||
|
||||
try {
|
||||
collectionTypes.add(ClassUtils.forName("io.vavr.collection.Seq", classLoader));
|
||||
} catch (ClassNotFoundException o_O) {}
|
||||
|
||||
try {
|
||||
collectionTypes.add(ClassUtils.forName("io.vavr.collection.Set", classLoader));
|
||||
} catch (ClassNotFoundException o_O) {}
|
||||
|
||||
COLLECTION_TYPES = collectionTypes.toArray(new Class[0]);
|
||||
}
|
||||
|
||||
ResolvableType resolvableType;
|
||||
private Map<String, Optional<TypeInformation<?>>> fields = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentLruCache<ResolvableType, TypeInformation<?>> CACHE = new ConcurrentLruCache<>(64,
|
||||
TypeDiscoverer::new);
|
||||
|
||||
private final ResolvableType resolvableType;
|
||||
private final Map<String, Optional<TypeInformation<?>>> fields = new ConcurrentHashMap<>();
|
||||
private final Lazy<TypeInformation<?>> componentType;
|
||||
private final Lazy<TypeInformation<?>> valueType;
|
||||
private final Map<Constructor<?>, List<TypeInformation<?>>> constructorParameters = new ConcurrentHashMap<>();
|
||||
private final Lazy<List<TypeInformation<?>>> typeArguments;
|
||||
|
||||
public TypeDiscoverer(Class<?> type) {
|
||||
this(ResolvableType.forClass(type));
|
||||
}
|
||||
|
||||
public TypeDiscoverer(ResolvableType type) {
|
||||
protected TypeDiscoverer(ResolvableType type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
this.resolvableType = type;
|
||||
this.componentType = Lazy.of(this::doGetComponentType);
|
||||
this.valueType = Lazy.of(this::doGetMapValueType);
|
||||
this.typeArguments = Lazy.of(this::doGetTypeArguments);
|
||||
}
|
||||
|
||||
static TypeDiscoverer<?> td(ResolvableType type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
return (TypeDiscoverer<?>) CACHE.get(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,16 +85,16 @@ public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
Assert.notNull(constructor, "Constructor must not be null");
|
||||
|
||||
List<TypeInformation<?>> target = new ArrayList<>();
|
||||
for (int i = 0; i < constructor.getParameterCount(); i++) {
|
||||
target.add(new TypeDiscoverer<>(ResolvableType.forConstructorParameter(constructor, i)));
|
||||
}
|
||||
return target;
|
||||
}
|
||||
return constructorParameters.computeIfAbsent(constructor, it -> {
|
||||
|
||||
@Override
|
||||
public TypeDescriptor toTypeDescriptor() {
|
||||
return new TypeDescriptor(resolvableType, null, null);
|
||||
List<TypeInformation<?>> target = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < it.getParameterCount(); i++) {
|
||||
target.add(TypeInformation.of(ResolvableType.forConstructorParameter(it, i)));
|
||||
}
|
||||
|
||||
return target;
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -137,56 +117,11 @@ public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
return info.getProperty(name.substring(separatorIndex + 1));
|
||||
}
|
||||
|
||||
private Optional<TypeInformation<?>> getPropertyInformation(String fieldname) {
|
||||
|
||||
Class<?> rawType = resolvableType.toClass();
|
||||
var field = ReflectionUtils.findField(rawType, fieldname);
|
||||
|
||||
if (field != null) {
|
||||
return Optional.of(new TypeDiscoverer(ResolvableType.forField(field, resolvableType)));
|
||||
}
|
||||
|
||||
return findPropertyDescriptor(rawType, fieldname).map(it -> {
|
||||
|
||||
if (it.getReadMethod() != null) {
|
||||
return new TypeDiscoverer(ResolvableType.forMethodReturnType(it.getReadMethod(), rawType));
|
||||
}
|
||||
if (it.getWriteMethod() != null) {
|
||||
return new TypeDiscoverer(ResolvableType.forMethodParameter(it.getWriteMethod(), 0, rawType));
|
||||
}
|
||||
|
||||
return new TypeDiscoverer(ResolvableType.forType(it.getPropertyType(), resolvableType));
|
||||
});
|
||||
}
|
||||
|
||||
private Optional<PropertyDescriptor> findPropertyDescriptor(Class<?> type, String fieldname) {
|
||||
|
||||
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(type, fieldname);
|
||||
|
||||
if (descriptor != null) {
|
||||
return Optional.of(descriptor);
|
||||
}
|
||||
|
||||
List<Class<?>> superTypes = new ArrayList<>();
|
||||
superTypes.addAll(Arrays.asList(type.getInterfaces()));
|
||||
superTypes.add(type.getSuperclass());
|
||||
|
||||
return Streamable.of(type.getInterfaces()).stream()//
|
||||
.flatMap(it -> Optionals.toStream(findPropertyDescriptor(it, fieldname)))//
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollectionLike() {
|
||||
|
||||
Class<S> type = getType();
|
||||
|
||||
for (Class<?> collectionType : COLLECTION_TYPES) {
|
||||
if (collectionType.isAssignableFrom(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return type.isArray() //
|
||||
|| Iterable.class.equals(type) //
|
||||
|| Collection.class.isAssignableFrom(type) //
|
||||
@@ -203,66 +138,27 @@ public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
@Nullable
|
||||
protected TypeInformation<?> doGetComponentType() {
|
||||
|
||||
var rawType = getType();
|
||||
|
||||
if (rawType.isArray()) {
|
||||
return new TypeDiscoverer<>(resolvableType.getComponentType());
|
||||
if (resolvableType.isArray()) {
|
||||
return TypeInformation.of(resolvableType.getComponentType());
|
||||
}
|
||||
|
||||
if (isMap()) {
|
||||
if (ClassUtils.isAssignable(Map.class, rawType)) {
|
||||
ResolvableType mapValueType = resolvableType.asMap().getGeneric(0);
|
||||
if (ResolvableType.NONE.equals(mapValueType)) {
|
||||
return null;
|
||||
}
|
||||
Class<S> rawType = getType();
|
||||
|
||||
return mapValueType != null ? new TypeDiscoverer(mapValueType) : new ClassTypeInformation<>(Object.class);
|
||||
}
|
||||
if (resolvableType.hasGenerics()) {
|
||||
ResolvableType mapValueType = resolvableType.getGeneric(0);
|
||||
return mapValueType != null ? new TypeDiscoverer(mapValueType) : new ClassTypeInformation<>(Object.class);
|
||||
}
|
||||
return Arrays.stream(resolvableType.getInterfaces()).filter(ResolvableType::hasGenerics)
|
||||
.findFirst()
|
||||
.map(it -> it.getGeneric(0))
|
||||
.map(TypeDiscoverer::new)
|
||||
.orElse(null);
|
||||
if (isMap()) {
|
||||
return getTypeArgument(CustomCollections.getMapBaseType(rawType), 0);
|
||||
}
|
||||
|
||||
if (Iterable.class.isAssignableFrom(rawType)) {
|
||||
|
||||
ResolvableType iterableType = resolvableType.as(Iterable.class);
|
||||
ResolvableType mapValueType = iterableType.getGeneric(0);
|
||||
if (ResolvableType.NONE.equals(mapValueType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (resolvableType.hasGenerics()) {
|
||||
mapValueType = resolvableType.getGeneric(0);
|
||||
return mapValueType != null ? new TypeDiscoverer(mapValueType) : new ClassTypeInformation<>(Object.class);
|
||||
}
|
||||
|
||||
return mapValueType.resolve() != null ? new TypeDiscoverer<>(mapValueType) : null;
|
||||
return getTypeArgument(Iterable.class, 0);
|
||||
}
|
||||
|
||||
if (isNullableWrapper()) {
|
||||
ResolvableType mapValueType = resolvableType.getGeneric(0);
|
||||
if (ResolvableType.NONE.equals(mapValueType)) {
|
||||
return null;
|
||||
}
|
||||
return mapValueType != null ? new TypeDiscoverer(mapValueType) : new ClassTypeInformation<>(Object.class);
|
||||
return getTypeArgument(rawType, 0);
|
||||
}
|
||||
|
||||
if (resolvableType.hasGenerics()) {
|
||||
ResolvableType mapValueType = resolvableType.getGeneric(0);
|
||||
return mapValueType != null ? new TypeDiscoverer(mapValueType) : new ClassTypeInformation<>(Object.class);
|
||||
}
|
||||
List<TypeInformation<?>> arguments = getTypeArguments();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isNullableWrapper() {
|
||||
return NullableWrapperConverters.supports(getType());
|
||||
return arguments.size() > 0 ? arguments.get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -279,50 +175,31 @@ public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
@Nullable
|
||||
protected TypeInformation<?> doGetMapValueType() {
|
||||
|
||||
if (isMap()) {
|
||||
if (ClassUtils.isAssignable(Map.class, getType())) {
|
||||
ResolvableType mapValueType = resolvableType.asMap().getGeneric(1);
|
||||
if (ResolvableType.NONE.equals(mapValueType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return mapValueType != null ? new TypeDiscoverer(mapValueType) : new ClassTypeInformation<>(Object.class);
|
||||
}
|
||||
if (resolvableType.hasGenerics()) {
|
||||
ResolvableType mapValueType = resolvableType.getGeneric(1);
|
||||
return mapValueType != null ? new TypeDiscoverer(mapValueType) : new ClassTypeInformation<>(Object.class);
|
||||
}
|
||||
return Arrays.stream(resolvableType.getInterfaces()).filter(ResolvableType::hasGenerics)
|
||||
.findFirst()
|
||||
.map(it -> it.getGeneric(1))
|
||||
.map(TypeDiscoverer::new)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (!resolvableType.hasGenerics()) {
|
||||
return null;
|
||||
}
|
||||
ResolvableType x = Arrays.stream(resolvableType.getGenerics()).skip(1).findFirst().orElse(null);
|
||||
if ((x == null) || ResolvableType.NONE.equals(x)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TypeDiscoverer<>(x);
|
||||
return isMap() //
|
||||
? getTypeArgument(CustomCollections.getMapBaseType(getType()), 1)
|
||||
: getTypeArguments().stream().skip(1).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<S> getType() {
|
||||
return (Class<S>) resolvableType.toClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor toTypeDescriptor() {
|
||||
return new TypeDescriptor(resolvableType, getType(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassTypeInformation<?> getRawTypeInformation() {
|
||||
return new ClassTypeInformation<>(this.resolvableType.getRawClass());
|
||||
return new ClassTypeInformation<>(ResolvableType.forRawClass(resolvableType.getRawClass()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TypeInformation<?> getActualType() {
|
||||
|
||||
if (isMap()) {
|
||||
return getMapValueType();
|
||||
}
|
||||
@@ -331,8 +208,6 @@ public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
return getComponentType();
|
||||
}
|
||||
|
||||
// TODO: Consider that we will support value types beyond Optional<T>, such as Json<T>, Foo<T> that should remain
|
||||
// configurable.
|
||||
if (isNullableWrapper()) {
|
||||
return getComponentType();
|
||||
}
|
||||
@@ -342,10 +217,7 @@ public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
@Override
|
||||
public TypeInformation<?> getReturnType(Method method) {
|
||||
|
||||
Assert.notNull(method, "Method must not be null");
|
||||
|
||||
return new TypeDiscoverer(ResolvableType.forMethodReturnType(method, getType()));
|
||||
return TypeInformation.of(ResolvableType.forMethodReturnType(method, getType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -353,9 +225,11 @@ public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
Assert.notNull(method, "Method most not be null");
|
||||
|
||||
return Streamable.of(method.getParameters()).stream().map(MethodParameter::forParameter)
|
||||
.map(it -> ResolvableType.forMethodParameter(it, resolvableType)).map(TypeDiscoverer::new)
|
||||
.collect(Collectors.toList());
|
||||
return Arrays.stream(method.getParameters()) //
|
||||
.map(MethodParameter::forParameter) //
|
||||
.map(it -> ResolvableType.forMethodParameter(it, resolvableType)) //
|
||||
.<TypeInformation<?>> map(TypeInformation::of) //
|
||||
.toList();
|
||||
|
||||
}
|
||||
|
||||
@@ -373,46 +247,24 @@ public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
return this;
|
||||
}
|
||||
|
||||
List<ResolvableType> candidates = new ArrayList<>();
|
||||
var resolvableSuperType = resolvableType.as(superType);
|
||||
var type = resolvableType.getType();
|
||||
|
||||
ResolvableType genericSuperclass = resolvableType.getSuperType();
|
||||
if ((genericSuperclass != null) && !genericSuperclass.equals(ResolvableType.NONE)) {
|
||||
candidates.add(genericSuperclass);
|
||||
if (!(type instanceof Class) || !ObjectUtils.isEmpty(((Class<?>) type).getTypeParameters())) {
|
||||
return TypeInformation.of(resolvableSuperType);
|
||||
}
|
||||
|
||||
candidates.addAll(Arrays.asList(resolvableType.getInterfaces()));
|
||||
var noGenericsResolvable = !Arrays.stream(resolvableSuperType.resolveGenerics())
|
||||
.filter(it -> it != null)
|
||||
.findAny()
|
||||
.isPresent();
|
||||
|
||||
for (var candidate : candidates) {
|
||||
if (ObjectUtils.nullSafeEquals(superType, candidate.toClass())) {
|
||||
|
||||
if (resolvableType.getType() instanceof Class) {
|
||||
|
||||
if (ObjectUtils.isEmpty(((Class) resolvableType.getType()).getTypeParameters())) {
|
||||
Class<?>[] classes = candidate.resolveGenerics(null);
|
||||
|
||||
if (!Arrays.stream(classes).filter(it -> it != null).findAny().isPresent()) {
|
||||
return new TypeDiscoverer<>(ResolvableType.forRawClass(superType));
|
||||
}
|
||||
}
|
||||
}
|
||||
return new TypeDiscoverer(ResolvableType.forClass(superType, getType()));
|
||||
} else {
|
||||
var sup = candidate.getSuperType();
|
||||
if ((sup != null) && !ResolvableType.NONE.equals(sup)) {
|
||||
if (sup.equals(resolvableType)) {
|
||||
return this;
|
||||
}
|
||||
return new TypeDiscoverer(sup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new TypeDiscoverer(resolvableType.as(superType));
|
||||
return noGenericsResolvable
|
||||
? new ClassTypeInformation<>(ResolvableType.forRawClass(superType))
|
||||
: TypeInformation.of(resolvableSuperType);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#isAssignableFrom(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Override
|
||||
public boolean isAssignableFrom(TypeInformation<?> target) {
|
||||
|
||||
TypeInformation<?> superTypeInformation = target.getSuperTypeInformation(getType());
|
||||
@@ -420,6 +272,7 @@ public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
if (superTypeInformation == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (superTypeInformation.equals(this)) {
|
||||
return true;
|
||||
}
|
||||
@@ -433,62 +286,58 @@ public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
@Override
|
||||
public List<TypeInformation<?>> getTypeArguments() {
|
||||
return typeArguments.get();
|
||||
}
|
||||
|
||||
private List<TypeInformation<?>> doGetTypeArguments() {
|
||||
|
||||
if (!resolvableType.hasGenerics()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Arrays.stream(resolvableType.getGenerics()).map(it -> {
|
||||
if ((it == null) || ResolvableType.NONE.equals(it)) {
|
||||
return null;
|
||||
}
|
||||
return new TypeDiscoverer<>(it);
|
||||
|
||||
}).collect(Collectors.toList());
|
||||
return Arrays.stream(resolvableType.getGenerics())
|
||||
.<TypeInformation<?>> map(it -> it.resolve(Object.class) == null ? null : TypeInformation.of(it))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeInformation<? extends S> specialize(ClassTypeInformation<?> type) {
|
||||
// if(isAssignableFrom(type)) {
|
||||
// return new ClassTypeInformation(type.getType());
|
||||
// }
|
||||
// return new NewTypeDiscoverer(type.resolvableType.as(getType()));
|
||||
// if(type.resolvableType.isAssignableFrom(type.resolvableType)) {
|
||||
// return (TypeInformation<? extends S>) type;
|
||||
// }
|
||||
@SuppressWarnings("unchecked")
|
||||
public TypeInformation<? extends S> specialize(TypeInformation<?> type) {
|
||||
|
||||
if (this.resolvableType.getGenerics().length == type.resolvableType.getGenerics().length) {
|
||||
return new TypeDiscoverer<>(
|
||||
if (this.getTypeArguments().size() == type.getTypeArguments().size()) {
|
||||
return (TypeInformation<? extends S>) TypeInformation.of(
|
||||
ResolvableType.forClassWithGenerics(type.getType(), this.resolvableType.getGenerics()));
|
||||
}
|
||||
|
||||
return new ClassTypeInformation(type.getType());
|
||||
return TypeInformation.of((Class<S>) type.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
public boolean equals(@Nullable Object o) {
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((o == null) || !ClassUtils.isAssignable(getClass(), o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeDiscoverer<?> that = (TypeDiscoverer<?>) o;
|
||||
var that = (TypeDiscoverer<?>) o;
|
||||
|
||||
if (!ObjectUtils.nullSafeEquals(getType(), that.getType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<? extends Class<?>> collect1 = Arrays.stream(resolvableType.getGenerics()).map(ResolvableType::toClass)
|
||||
.collect(Collectors.toList());
|
||||
List<? extends Class<?>> collect2 = Arrays.stream(that.resolvableType.getGenerics()).map(ResolvableType::toClass)
|
||||
var collect1 = Arrays.stream(resolvableType.getGenerics()) //
|
||||
.map(ResolvableType::toClass) //
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!ObjectUtils.nullSafeEquals(collect1, collect2)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
var collect2 = Arrays.stream(that.resolvableType.getGenerics()) //
|
||||
.map(ResolvableType::toClass) //
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return ObjectUtils.nullSafeEquals(collect1, collect2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -498,6 +347,57 @@ public class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getType().getName();
|
||||
return resolvableType.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TypeInformation<?> getTypeArgument(Class<?> bound, int index) {
|
||||
|
||||
var superTypeInformation = getSuperTypeInformation(bound);
|
||||
|
||||
if (superTypeInformation == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var arguments = superTypeInformation.getTypeArguments();
|
||||
|
||||
if (arguments.isEmpty() || (index > (arguments.size() - 1))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return arguments.get(index);
|
||||
}
|
||||
|
||||
private Optional<TypeInformation<?>> getPropertyInformation(String fieldname) {
|
||||
|
||||
var rawType = getType();
|
||||
var field = ReflectionUtils.findField(rawType, fieldname);
|
||||
|
||||
return field != null
|
||||
? Optional.of(TypeInformation.of(ResolvableType.forField(field, resolvableType)))
|
||||
: Optional.ofNullable(BeanUtils.getPropertyDescriptor(rawType, fieldname))
|
||||
.map(it -> from(it, rawType))
|
||||
.map(TypeInformation::of);
|
||||
}
|
||||
|
||||
private ResolvableType from(PropertyDescriptor descriptor, Class<?> rawType) {
|
||||
|
||||
var method = descriptor.getReadMethod();
|
||||
|
||||
if (method != null) {
|
||||
return ResolvableType.forMethodReturnType(method, rawType);
|
||||
}
|
||||
|
||||
method = descriptor.getWriteMethod();
|
||||
|
||||
if (method != null) {
|
||||
return ResolvableType.forMethodParameter(method, 0, rawType);
|
||||
}
|
||||
|
||||
return ResolvableType.forType(descriptor.getPropertyType(), resolvableType);
|
||||
}
|
||||
|
||||
private boolean isNullableWrapper() {
|
||||
return NullableWrapperConverters.supports(getType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,15 @@ package org.springframework.data.util;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Interface to access property types and resolving generics on the way. Starting with a {@link ClassTypeInformation}
|
||||
@@ -30,9 +35,77 @@ import org.springframework.lang.Nullable;
|
||||
* @author Mark Paluch
|
||||
* @author Alessandro Nistico
|
||||
* @author Johannes Englmeier
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@SuppressWarnings({ "deprecation", "rawtypes" })
|
||||
public interface TypeInformation<S> {
|
||||
|
||||
public static final TypeInformation<Collection> COLLECTION = ClassTypeInformation.COLLECTION;
|
||||
public static final TypeInformation<List> LIST = ClassTypeInformation.LIST;
|
||||
public static final TypeInformation<Set> SET = ClassTypeInformation.SET;
|
||||
public static final TypeInformation<Map> MAP = ClassTypeInformation.MAP;
|
||||
public static final TypeInformation<Object> OBJECT = ClassTypeInformation.OBJECT;
|
||||
|
||||
static TypeInformation<?> orObject(@Nullable ResolvableType type) {
|
||||
return type == null ? ClassTypeInformation.OBJECT : of(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypeInformation} from the given {@link ResolvableType}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static TypeInformation<?> of(ResolvableType type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
return type.hasGenerics() || (type.isArray() && type.getComponentType().hasGenerics()) //
|
||||
? TypeDiscoverer.td(type)
|
||||
: ClassTypeInformation.cti(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypeInformation} for the given {@link Class}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static <S> TypeInformation<S> of(Class<S> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
return ClassTypeInformation.from(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link TypeInformation} for the given {@link Method}.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static TypeInformation<?> fromReturnTypeOf(Method method) {
|
||||
|
||||
Assert.notNull(method, "Method must not be null");
|
||||
|
||||
return fromReturnTypeOf(method, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link TypeInformation} for the given method as declared on the given type.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @param type can be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static TypeInformation<?> fromReturnTypeOf(Method method, @Nullable Class<?> type) {
|
||||
return ClassTypeInformation.fromReturnTypeOf(method, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation}s for the parameters of the given {@link Constructor}.
|
||||
*
|
||||
@@ -162,7 +235,7 @@ public interface TypeInformation<S> {
|
||||
default TypeInformation<?> getUserTypeInformation() {
|
||||
|
||||
Class<?> userType = ProxyUtils.getUserClass(getType());
|
||||
return userType.equals(getType()) ? this : ClassTypeInformation.from(userType);
|
||||
return userType.equals(getType()) ? this : TypeInformation.of(userType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,12 +349,27 @@ public interface TypeInformation<S> {
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
* @deprecated since 3.0. Use {@link #specialize(TypeInformation)} instead, i.e. switch the given parameter's type to
|
||||
* {@link TypeInformation} in the first place.
|
||||
*/
|
||||
TypeInformation<? extends S> specialize(ClassTypeInformation<?> type);
|
||||
|
||||
default TypeInformation<? extends S> specialize(TypeInformation<?> type) {
|
||||
return specialize(ClassTypeInformation.from(type.getType()));
|
||||
@Deprecated
|
||||
default TypeInformation<? extends S> specialize(ClassTypeInformation<?> type) {
|
||||
return specialize((TypeInformation<?>) type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specializes the given (raw) {@link TypeInformation} using the context of the current potentially parameterized
|
||||
* type, basically turning the given raw type into a parameterized one. Will return the given type as is if no
|
||||
* generics are involved.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default TypeInformation<? extends S> specialize(TypeInformation<?> type) {
|
||||
return (TypeInformation<? extends S>) type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the current type is a sub type of the given one, i.e. whether it's assignable but not the same one.
|
||||
*
|
||||
|
||||
@@ -29,12 +29,10 @@ import java.util.Map;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.projection.Accessor;
|
||||
import org.springframework.data.projection.MethodInterceptorFactory;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -146,7 +144,7 @@ public class JsonProjectingMethodInterceptorFactory implements MethodInterceptor
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
|
||||
Method method = invocation.getMethod();
|
||||
TypeInformation<?> returnType = ClassTypeInformation.fromReturnTypeOf(method);
|
||||
TypeInformation<?> returnType = TypeInformation.fromReturnTypeOf(method);
|
||||
ResolvableType type = ResolvableType.forMethodReturnType(method);
|
||||
boolean isCollectionResult = Collection.class.isAssignableFrom(type.getRawClass());
|
||||
type = isCollectionResult ? type : ResolvableType.forClassWithGenerics(List.class, type);
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.springframework.data.querydsl.binding.QuerydslBindingsFactory;
|
||||
import org.springframework.data.querydsl.binding.QuerydslPredicate;
|
||||
import org.springframework.data.querydsl.binding.QuerydslPredicateBuilder;
|
||||
import org.springframework.data.util.CastUtils;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -135,7 +134,7 @@ public abstract class QuerydslPredicateArgumentResolverSupport {
|
||||
Optional<QuerydslPredicate> annotation = predicateAnnotation.synthesize(MergedAnnotation::isPresent);
|
||||
|
||||
return annotation.filter(it -> !Object.class.equals(it.root()))//
|
||||
.<TypeInformation<?>> map(it -> ClassTypeInformation.from(it.root()))//
|
||||
.<TypeInformation<?>> map(it -> TypeInformation.of(it.root()))//
|
||||
.orElseGet(() -> detectDomainType(parameter));
|
||||
}
|
||||
|
||||
@@ -147,7 +146,7 @@ public abstract class QuerydslPredicateArgumentResolverSupport {
|
||||
throw new IllegalArgumentException("Method parameter is not backed by a method");
|
||||
}
|
||||
|
||||
return detectDomainType(ClassTypeInformation.fromReturnTypeOf(method));
|
||||
return detectDomainType(TypeInformation.fromReturnTypeOf(method));
|
||||
}
|
||||
|
||||
private static TypeInformation<?> detectDomainType(TypeInformation<?> source) {
|
||||
|
||||
Reference in New Issue
Block a user