DATACMNS-1101 - Remove Optional from TypeDiscoverer API.
This commit is contained in:
committed by
Oliver Gierke
parent
2064c72a85
commit
0493d131e0
@@ -34,9 +34,10 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstraction of a {@link PropertyPath} of a domain class.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
public class PropertyPath implements Streamable<PropertyPath> {
|
||||
@@ -56,7 +57,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
/**
|
||||
* Creates a leaf {@link PropertyPath} (no nested ones) with the given name inside the given owning type.
|
||||
*
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param owningType must not be {@literal null}.
|
||||
*/
|
||||
@@ -66,7 +67,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
/**
|
||||
* Creates a leaf {@link PropertyPath} (no nested ones with the given name and owning type.
|
||||
*
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param owningType must not be {@literal null}.
|
||||
* @param base the {@link PropertyPath} previously found.
|
||||
@@ -78,8 +79,11 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
Assert.notNull(base, "Perviously found properties must not be null!");
|
||||
|
||||
String propertyName = name.matches(ALL_UPPERCASE) ? name : StringUtils.uncapitalize(name);
|
||||
TypeInformation<?> propertyType = owningType.getProperty(propertyName)
|
||||
.orElseThrow(() -> new PropertyReferenceException(propertyName, owningType, base));
|
||||
TypeInformation<?> propertyType = owningType.getProperty(propertyName);
|
||||
|
||||
if (propertyType == null) {
|
||||
throw new PropertyReferenceException(propertyName, owningType, base);
|
||||
}
|
||||
|
||||
this.owningType = owningType;
|
||||
this.typeInformation = propertyType;
|
||||
@@ -90,7 +94,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
/**
|
||||
* Returns the owning type of the {@link PropertyPath}.
|
||||
*
|
||||
*
|
||||
* @return the owningType will never be {@literal null}.
|
||||
*/
|
||||
public TypeInformation<?> getOwningType() {
|
||||
@@ -99,7 +103,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
/**
|
||||
* Returns the name of the {@link PropertyPath}.
|
||||
*
|
||||
*
|
||||
* @return the name will never be {@literal null}.
|
||||
*/
|
||||
public String getSegment() {
|
||||
@@ -108,7 +112,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
/**
|
||||
* Returns the leaf property of the {@link PropertyPath}.
|
||||
*
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public PropertyPath getLeafProperty() {
|
||||
@@ -125,7 +129,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
/**
|
||||
* Returns the type of the property will return the plain resolved type for simple properties, the component type for
|
||||
* any {@link Iterable} or the value type of a {@link java.util.Map} if the property is one.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
@@ -134,7 +138,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
/**
|
||||
* Returns the next nested {@link PropertyPath}.
|
||||
*
|
||||
*
|
||||
* @return the next nested {@link PropertyPath} or {@literal null} if no nested {@link PropertyPath} available.
|
||||
* @see #hasNext()
|
||||
*/
|
||||
@@ -145,7 +149,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
/**
|
||||
* Returns whether there is a nested {@link PropertyPath}. If this returns {@literal true} you can expect
|
||||
* {@link #next()} to return a non- {@literal null} value.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
@@ -154,7 +158,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
/**
|
||||
* Returns the {@link PropertyPath} in dot notation.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String toDotPath() {
|
||||
@@ -168,14 +172,14 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PropertyPath} is actually a collection.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isCollection() {
|
||||
return isCollection;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
@@ -202,7 +206,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
/**
|
||||
* Extracts the {@link PropertyPath} chain from the given source {@link String} and type.
|
||||
*
|
||||
*
|
||||
* @param source
|
||||
* @param type
|
||||
* @return
|
||||
@@ -213,7 +217,8 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
/**
|
||||
* Extracts the {@link PropertyPath} chain from the given source {@link String} and {@link TypeInformation}. <br />
|
||||
* Uses {@link #SPLITTER} by default and {@link #SPLITTER_FOR_QUOTED} for {@link Pattern#quote(String) quoted} literals.
|
||||
* Uses {@link #SPLITTER} by default and {@link #SPLITTER_FOR_QUOTED} for {@link Pattern#quote(String) quoted}
|
||||
* literals.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param type
|
||||
@@ -256,7 +261,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyPath} as subordinary of the given {@link PropertyPath}.
|
||||
*
|
||||
*
|
||||
* @param source
|
||||
* @param base
|
||||
* @return
|
||||
@@ -275,7 +280,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
* the given source for camel-case parts and traverse the {@link String} along its parts starting with the entire one
|
||||
* and chewing off parts from the right side then. Whenever a valid property for the given class is found, the tail
|
||||
* will be traversed for subordinary properties of the just found one and so on.
|
||||
*
|
||||
*
|
||||
* @param source
|
||||
* @param type
|
||||
* @return
|
||||
@@ -288,7 +293,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
* Tries to look up a chain of {@link PropertyPath}s by trying the givne source first. If that fails it will split the
|
||||
* source apart at camel case borders (starting from the right side) and try to look up a {@link PropertyPath} from
|
||||
* the calculated head and recombined new tail and additional tail.
|
||||
*
|
||||
*
|
||||
* @param source
|
||||
* @param type
|
||||
* @param addTail
|
||||
@@ -344,7 +349,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
|
||||
@@ -268,7 +268,16 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getMapValueType() {
|
||||
return isMap() ? information.getMapValueType().map(TypeInformation::getType).orElse(null) : null;
|
||||
|
||||
if (isMap()) {
|
||||
|
||||
TypeInformation<?> mapValueType = information.getMapValueType();
|
||||
if (mapValueType != null) {
|
||||
return mapValueType.getType();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -37,11 +37,12 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Abstraction of a method that is designated to execute a finder query. Enriches the standard {@link Method} interface
|
||||
* with specific information that is necessary to construct {@link RepositoryQuery}s for the method.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Maciek Opała
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class QueryMethod {
|
||||
|
||||
@@ -55,7 +56,7 @@ public class QueryMethod {
|
||||
/**
|
||||
* Creates a new {@link QueryMethod} from the given parameters. Looks up the correct query to use for following
|
||||
* invocations of the method given.
|
||||
*
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @param metadata must not be {@literal null}.
|
||||
* @param factory must not be {@literal null}.
|
||||
@@ -113,7 +114,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Creates a {@link Parameters} instance.
|
||||
*
|
||||
*
|
||||
* @param method
|
||||
* @return must not return {@literal null}.
|
||||
*/
|
||||
@@ -123,7 +124,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns the method's name.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
@@ -137,7 +138,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns the name of the named query this method belongs to.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getNamedQueryName() {
|
||||
@@ -146,7 +147,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns the domain class the query method is targeted at.
|
||||
*
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
protected Class<?> getDomainClass() {
|
||||
@@ -155,7 +156,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns the type of the object that will be returned.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<?> getReturnedObjectType() {
|
||||
@@ -164,7 +165,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns whether the finder will actually return a collection of entities or a single one.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isCollectionQuery() {
|
||||
@@ -190,7 +191,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns whether the query method will return a {@link Slice}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @since 1.8
|
||||
*/
|
||||
@@ -200,7 +201,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns whether the finder will return a {@link Page} of results.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public final boolean isPageQuery() {
|
||||
@@ -209,7 +210,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns whether the query method is a modifying one.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isModifyingQuery() {
|
||||
@@ -218,7 +219,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns whether the query for this method actually returns entities.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isQueryForEntity() {
|
||||
@@ -227,7 +228,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns whether the method returns a Stream.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
@@ -237,7 +238,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns the {@link Parameters} wrapper to gain additional information about {@link Method} parameters.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Parameters<?, ?> getParameters() {
|
||||
@@ -246,7 +247,7 @@ public class QueryMethod {
|
||||
|
||||
/**
|
||||
* Returns the {@link ResultProcessor} to be used with the query method.
|
||||
*
|
||||
*
|
||||
* @return the resultFactory
|
||||
*/
|
||||
public ResultProcessor getResultProcessor() {
|
||||
@@ -265,10 +266,17 @@ public class QueryMethod {
|
||||
private static Class<? extends Object> potentiallyUnwrapReturnTypeFor(Method method) {
|
||||
|
||||
if (QueryExecutionConverters.supports(method.getReturnType())) {
|
||||
|
||||
// unwrap only one level to handle cases like Future<List<Entity>> correctly.
|
||||
return ClassTypeInformation.fromReturnTypeOf(method).getComponentType().map(TypeInformation::getType)
|
||||
.orElseThrow(() -> new IllegalStateException(
|
||||
String.format("Couldn't find component type for return value of method %s!", method)));
|
||||
|
||||
TypeInformation<?> componentType = ClassTypeInformation.fromReturnTypeOf(method).getComponentType();
|
||||
|
||||
if (componentType == null) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Couldn't find component type for return value of method %s!", method));
|
||||
}
|
||||
|
||||
return componentType.getType();
|
||||
}
|
||||
|
||||
return method.getReturnType();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,11 +20,10 @@ import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Special {@link TypeDiscoverer} handling {@link GenericArrayType}s.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class GenericArrayTypeInformation<S> extends ParentTypeAwareTypeInformation<S> {
|
||||
@@ -34,7 +33,7 @@ class GenericArrayTypeInformation<S> extends ParentTypeAwareTypeInformation<S> {
|
||||
/**
|
||||
* Creates a new {@link GenericArrayTypeInformation} for the given {@link GenericArrayTypeInformation} and
|
||||
* {@link TypeDiscoverer}.
|
||||
*
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param parent must not be {@literal null}.
|
||||
* @param typeVariableMap must not be {@literal null}.
|
||||
@@ -61,13 +60,13 @@ class GenericArrayTypeInformation<S> extends ParentTypeAwareTypeInformation<S> {
|
||||
* @see org.springframework.data.util.TypeDiscoverer#doGetComponentType()
|
||||
*/
|
||||
@Override
|
||||
protected Optional<TypeInformation<?>> doGetComponentType() {
|
||||
protected TypeInformation<?> doGetComponentType() {
|
||||
|
||||
Type componentType = type.getGenericComponentType();
|
||||
return Optional.of(createInfo(componentType));
|
||||
return createInfo(componentType);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.springframework.util.StringUtils;
|
||||
/**
|
||||
* Base class for all types that include parameterization of some kind. Crucial as we have to take note of the parent
|
||||
* class we will have to resolve generic parameters against.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
@@ -43,7 +43,7 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
|
||||
/**
|
||||
* Creates a new {@link ParameterizedTypeInformation} for the given {@link Type} and parent {@link TypeDiscoverer}.
|
||||
*
|
||||
*
|
||||
* @param type must not be {@literal null}
|
||||
* @param parent must not be {@literal null}
|
||||
*/
|
||||
@@ -59,14 +59,14 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
* @see org.springframework.data.util.TypeDiscoverer#doGetMapValueType()
|
||||
*/
|
||||
@Override
|
||||
protected Optional<TypeInformation<?>> doGetMapValueType() {
|
||||
protected TypeInformation<?> doGetMapValueType() {
|
||||
|
||||
if (Map.class.isAssignableFrom(getType())) {
|
||||
|
||||
Type[] arguments = type.getActualTypeArguments();
|
||||
|
||||
if (arguments.length > 1) {
|
||||
return Optional.of(createInfo(arguments[1]));
|
||||
return createInfo(arguments[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,14 +79,14 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
Optional<TypeInformation<?>> result = supertypes.stream()//
|
||||
.map(it -> Pair.of(it, resolveType(it)))//
|
||||
.filter(it -> Map.class.isAssignableFrom(it.getSecond()))//
|
||||
.<TypeInformation<?>>map(it -> {
|
||||
.<TypeInformation<?>> map(it -> {
|
||||
|
||||
ParameterizedType parameterizedSupertype = (ParameterizedType) it.getFirst();
|
||||
Type[] arguments = parameterizedSupertype.getActualTypeArguments();
|
||||
return createInfo(arguments[1]);
|
||||
}).findFirst();
|
||||
|
||||
return result.isPresent() ? result : super.doGetMapValueType();
|
||||
return result.orElseGet(super::doGetMapValueType);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -105,7 +105,7 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#isAssignableFrom(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@@ -147,11 +147,11 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
* @see org.springframework.data.util.TypeDiscoverer#doGetComponentType()
|
||||
*/
|
||||
@Override
|
||||
protected Optional<TypeInformation<?>> doGetComponentType() {
|
||||
return Optional.of(createInfo(type.getActualTypeArguments()[0]));
|
||||
protected TypeInformation<?> doGetComponentType() {
|
||||
return createInfo(type.getActualTypeArguments()[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.ParentTypeAwareTypeInformation#equals(java.lang.Object)
|
||||
*/
|
||||
@@ -175,7 +175,7 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.ParentTypeAwareTypeInformation#hashCode()
|
||||
*/
|
||||
@@ -184,7 +184,7 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
return isResolvedCompletely() ? this.type.hashCode() : super.hashCode();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
|
||||
@@ -28,7 +28,16 @@ import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
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;
|
||||
|
||||
@@ -43,6 +52,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
@@ -68,8 +78,8 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
private final int hashCode;
|
||||
|
||||
private final Lazy<Class<S>> resolvedType;
|
||||
private final Lazy<Optional<TypeInformation<?>>> componentType;
|
||||
private final Lazy<Optional<TypeInformation<?>>> valueType;
|
||||
private final Lazy<TypeInformation<?>> componentType;
|
||||
private final Lazy<TypeInformation<?>> valueType;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypeDiscoverer} for the given type, type variable map and parent.
|
||||
@@ -99,19 +109,17 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
return typeVariableMap;
|
||||
}
|
||||
|
||||
private TypeInformation<?> createInfo(Optional<Type> fieldType) {
|
||||
return fieldType.map(this::createInfo).orElseThrow(IllegalArgumentException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link TypeInformation} for the given {@link Type}.
|
||||
*
|
||||
* @param fieldType
|
||||
* @param fieldType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked", "deprecation" })
|
||||
protected TypeInformation<?> createInfo(Type fieldType) {
|
||||
|
||||
Assert.notNull(fieldType, "Field type must not be null!");
|
||||
|
||||
if (fieldType.equals(this.type)) {
|
||||
return this;
|
||||
}
|
||||
@@ -203,18 +211,22 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getProperty(java.lang.String)
|
||||
*/
|
||||
public Optional<TypeInformation<?>> getProperty(String fieldname) {
|
||||
public TypeInformation<?> getProperty(String fieldname) {
|
||||
|
||||
int separatorIndex = fieldname.indexOf('.');
|
||||
|
||||
if (separatorIndex == -1) {
|
||||
return fieldTypes.computeIfAbsent(fieldname, this::getPropertyInformation);
|
||||
return fieldTypes.computeIfAbsent(fieldname, this::getPropertyInformation).orElse(null);
|
||||
}
|
||||
|
||||
String head = fieldname.substring(0, separatorIndex);
|
||||
Optional<TypeInformation<?>> info = getProperty(head);
|
||||
TypeInformation<?> info = getProperty(head);
|
||||
|
||||
return info.map(it -> it.getProperty(fieldname.substring(separatorIndex + 1))).orElseGet(Optional::empty);
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return info.getProperty(fieldname.substring(separatorIndex + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -235,7 +247,6 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
}
|
||||
|
||||
return findPropertyDescriptor(rawType, fieldname).map(it -> createInfo(getGenericType(it)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,22 +280,22 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
* @param descriptor must not be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
private static Optional<Type> getGenericType(PropertyDescriptor descriptor) {
|
||||
private static Type getGenericType(PropertyDescriptor descriptor) {
|
||||
|
||||
Method method = descriptor.getReadMethod();
|
||||
|
||||
if (method != null) {
|
||||
return Optional.of(method.getGenericReturnType());
|
||||
return method.getGenericReturnType();
|
||||
}
|
||||
|
||||
method = descriptor.getWriteMethod();
|
||||
|
||||
if (method == null) {
|
||||
return Optional.empty();
|
||||
return null;
|
||||
}
|
||||
|
||||
Type[] parameterTypes = method.getGenericParameterTypes();
|
||||
return Optional.ofNullable(parameterTypes.length == 0 ? null : parameterTypes[0]);
|
||||
return parameterTypes.length == 0 ? null : parameterTypes[0];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -311,11 +322,11 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
public TypeInformation<?> getActualType() {
|
||||
|
||||
if (isMap()) {
|
||||
return getMapValueType().orElse(null);
|
||||
return getMapValueType();
|
||||
}
|
||||
|
||||
if (isCollectionLike()) {
|
||||
return getComponentType().orElse(null);
|
||||
return getComponentType();
|
||||
}
|
||||
|
||||
return this;
|
||||
@@ -342,12 +353,13 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getMapValueType()
|
||||
*/
|
||||
public Optional<TypeInformation<?>> getMapValueType() {
|
||||
public TypeInformation<?> getMapValueType() {
|
||||
return valueType.get();
|
||||
}
|
||||
|
||||
protected Optional<TypeInformation<?>> doGetMapValueType() {
|
||||
return isMap() ? getTypeArgument(getBaseType(MAP_TYPES), 1) : getTypeArguments().stream().skip(1).findFirst();
|
||||
protected TypeInformation<?> doGetMapValueType() {
|
||||
return isMap() ? getTypeArgument(getBaseType(MAP_TYPES), 1)
|
||||
: getTypeArguments().stream().skip(1).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -365,16 +377,16 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getComponentType()
|
||||
*/
|
||||
public final Optional<TypeInformation<?>> getComponentType() {
|
||||
public final TypeInformation<?> getComponentType() {
|
||||
return componentType.get();
|
||||
}
|
||||
|
||||
protected Optional<TypeInformation<?>> doGetComponentType() {
|
||||
protected TypeInformation<?> doGetComponentType() {
|
||||
|
||||
Class<S> rawType = getType();
|
||||
|
||||
if (rawType.isArray()) {
|
||||
return Optional.of(createInfo(rawType.getComponentType()));
|
||||
return createInfo(rawType.getComponentType());
|
||||
}
|
||||
|
||||
if (isMap()) {
|
||||
@@ -387,7 +399,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
List<TypeInformation<?>> arguments = getTypeArguments();
|
||||
|
||||
return arguments.size() > 0 ? Optional.of(arguments.get(0)) : Optional.empty();
|
||||
return arguments.size() > 0 ? arguments.get(0) : null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -486,16 +498,16 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
: createInfo(new SyntheticParamterizedType(type, arguments)));
|
||||
}
|
||||
|
||||
private Optional<TypeInformation<?>> getTypeArgument(Class<?> bound, int index) {
|
||||
private TypeInformation<?> getTypeArgument(Class<?> bound, int index) {
|
||||
|
||||
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(getType(), bound);
|
||||
|
||||
if (arguments == null) {
|
||||
return Optional.ofNullable(
|
||||
getSuperTypeInformation(bound) instanceof ParameterizedTypeInformation ? ClassTypeInformation.OBJECT : null);
|
||||
return getSuperTypeInformation(bound) instanceof ParameterizedTypeInformation ? ClassTypeInformation.OBJECT
|
||||
: null;
|
||||
}
|
||||
|
||||
return Optional.of(createInfo(arguments[index]));
|
||||
return createInfo(arguments[index]);
|
||||
}
|
||||
|
||||
private Class<?> getBaseType(Class<?>[] candidates) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2015 the original author or authors.
|
||||
* Copyright 2008-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,19 +18,19 @@ package org.springframework.data.util;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Interface to access property types and resolving generics on the way. Starting with a {@link ClassTypeInformation}
|
||||
* you can traverse properties using {@link #getProperty(String)} to access type information.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface TypeInformation<S> {
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation}s for the parameters of the given {@link Constructor}.
|
||||
*
|
||||
*
|
||||
* @param constructor must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -39,69 +39,106 @@ public interface TypeInformation<S> {
|
||||
/**
|
||||
* Returns the property information for the property with the given name. Supports property traversal through dot
|
||||
* notation.
|
||||
*
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
Optional<TypeInformation<?>> getProperty(String property);
|
||||
TypeInformation<?> getProperty(String property);
|
||||
|
||||
/**
|
||||
* Returns the property information for the property with the given name or throw {@link IllegalArgumentException} if
|
||||
* the type information cannot be resolved. Supports property traversal through dot notation.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
* @throws IllegalArgumentException if the type information cannot be resolved.
|
||||
* @since 2.0
|
||||
*/
|
||||
default TypeInformation<?> getRequiredProperty(String property) {
|
||||
return getProperty(property).orElseThrow(() -> new IllegalArgumentException(
|
||||
String.format("Could not find required property %s on %s!", property, getType())));
|
||||
|
||||
TypeInformation<?> typeInformation = getProperty(property);
|
||||
|
||||
if (typeInformation != null) {
|
||||
return typeInformation;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Could not find required property %s on %s!", property, getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the type can be considered a collection, which means it's a container of elements, e.g. a
|
||||
* {@link java.util.Collection} and {@link java.lang.reflect.Array} or anything implementing {@link Iterable}. If this
|
||||
* returns {@literal true} you can expect {@link #getComponentType()} to return a non-{@literal null} value.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isCollectionLike();
|
||||
|
||||
/**
|
||||
* Returns the component type for {@link java.util.Collection}s or the key type for {@link java.util.Map}s.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Optional<TypeInformation<?>> getComponentType();
|
||||
TypeInformation<?> getComponentType();
|
||||
|
||||
/**
|
||||
* Returns the component type for {@link java.util.Collection}s, the key type for {@link java.util.Map}s or the single
|
||||
* generic type if available throwing an exception if it can't be resolved.
|
||||
*
|
||||
* generic type if available. Throws {@link IllegalStateException} if the component value type cannot be resolved.
|
||||
*
|
||||
* @return
|
||||
* @throws IllegalStateException if the component type cannot be resolved, e.g. if a raw type is used or the type is
|
||||
* not generic in the first place.
|
||||
* @since 2.0
|
||||
*/
|
||||
default TypeInformation<?> getRequiredComponentType() {
|
||||
return getComponentType().orElseThrow(
|
||||
() -> new IllegalStateException(String.format("Can't resolve required component type for %s!", getType())));
|
||||
|
||||
TypeInformation<?> componentType = getComponentType();
|
||||
|
||||
if (componentType != null) {
|
||||
return getComponentType();
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("Can't resolve required component type for %s!", getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the property is a {@link java.util.Map}. If this returns {@literal true} you can expect
|
||||
* {@link #getComponentType()} as well as {@link #getMapValueType()} to return something not {@literal null}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isMap();
|
||||
|
||||
/**
|
||||
* Will return the type of the value in case the underlying type is a {@link java.util.Map}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Optional<TypeInformation<?>> getMapValueType();
|
||||
TypeInformation<?> getMapValueType();
|
||||
|
||||
/**
|
||||
* Will return the type of the value in case the underlying type is a {@link java.util.Map} or throw
|
||||
* {@link IllegalStateException} if the map value type cannot be resolved.
|
||||
*
|
||||
* @return
|
||||
* @throws IllegalStateException if the map value type cannot be resolved.
|
||||
* @since 2.0
|
||||
*/
|
||||
default TypeInformation<?> getRequiredMapValueType() {
|
||||
return getMapValueType().orElseThrow(
|
||||
() -> new IllegalStateException(String.format("Can't resolve required map value type for %s!", getType())));
|
||||
|
||||
TypeInformation<?> mapValueType = getMapValueType();
|
||||
|
||||
if (mapValueType != null) {
|
||||
return mapValueType;
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("Can't resolve required map value type for %s!", getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the property. Will resolve generics and the generic context of
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Class<S> getType();
|
||||
@@ -109,7 +146,7 @@ public interface TypeInformation<S> {
|
||||
/**
|
||||
* Returns a {@link ClassTypeInformation} to represent the {@link TypeInformation} of the raw type of the current
|
||||
* instance.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
ClassTypeInformation<?> getRawTypeInformation();
|
||||
@@ -117,7 +154,7 @@ public interface TypeInformation<S> {
|
||||
/**
|
||||
* Transparently returns the {@link java.util.Map} value type if the type is a {@link java.util.Map}, returns the
|
||||
* component type if the type {@link #isCollectionLike()} or the simple type if none of this applies.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<?> getActualType();
|
||||
@@ -125,7 +162,7 @@ public interface TypeInformation<S> {
|
||||
/**
|
||||
* Returns a {@link TypeInformation} for the return type of the given {@link Method}. Will potentially resolve
|
||||
* generics information against the current types type parameter bindings.
|
||||
*
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -133,7 +170,7 @@ public interface TypeInformation<S> {
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation}s for the parameters of the given {@link Method}.
|
||||
*
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -141,7 +178,7 @@ public interface TypeInformation<S> {
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} for the given raw super type.
|
||||
*
|
||||
*
|
||||
* @param superType must not be {@literal null}.
|
||||
* @return the {@link TypeInformation} for the given raw super type or {@literal null} in case the current
|
||||
* {@link TypeInformation} does not implement the given type.
|
||||
@@ -152,7 +189,7 @@ public interface TypeInformation<S> {
|
||||
* Returns if the current {@link TypeInformation} can be safely assigned to the given one. Mimics semantics of
|
||||
* {@link Class#isAssignableFrom(Class)} but takes generics into account. Thus it will allow to detect that a
|
||||
* {@code List<Long>} is assignable to {@code List<? extends Number>}.
|
||||
*
|
||||
*
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
@@ -160,7 +197,7 @@ public interface TypeInformation<S> {
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} for the type arguments of the current {@link TypeInformation}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<TypeInformation<?>> getTypeArguments();
|
||||
@@ -169,7 +206,7 @@ public interface TypeInformation<S> {
|
||||
* Specializes the given (raw) {@link ClassTypeInformation} 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}.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user