DATACMNS-266 - Use new common Maven build infrastructure.
Simplified project setup to be a single module build again. Using Spring Data Build parent POM to simplify project setup. See https://github.com/SpringSource/spring-data-build#spring-data-build-infrastructure
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2012 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.FieldCallback;
|
||||
|
||||
/**
|
||||
* A {@link FieldCallback} that will inspect each field for a given annotation. Thie fields type can then be accessed
|
||||
* afterwards.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class AnnotationDetectionFieldCallback implements FieldCallback {
|
||||
|
||||
private final Class<? extends Annotation> annotationType;
|
||||
private Field field;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationDetectionFieldCallback} scanning for an annotation of the given type.
|
||||
*
|
||||
* @param annotationType must not be {@literal null}.
|
||||
*/
|
||||
public AnnotationDetectionFieldCallback(Class<? extends Annotation> annotationType) {
|
||||
|
||||
Assert.notNull(annotationType);
|
||||
this.annotationType = annotationType;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.util.ReflectionUtils.FieldCallback#doWith(java.lang.reflect.Field)
|
||||
*/
|
||||
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
|
||||
|
||||
if (this.field != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Annotation annotation = field.getAnnotation(annotationType);
|
||||
if (annotation != null) {
|
||||
this.field = field;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the field.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return field == null ? null : field.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value of the field by reflection.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getValue(Object source) {
|
||||
|
||||
Assert.notNull(source);
|
||||
return field == null ? null : (T) ReflectionUtils.getField(field, source);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link TypeInformation} for a plain {@link Class}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
|
||||
|
||||
public static final TypeInformation<Collection> COLLECTION = new ClassTypeInformation(Collection.class);
|
||||
public static final TypeInformation<List> LIST = new ClassTypeInformation(List.class);
|
||||
public static final TypeInformation<Set> SET = new ClassTypeInformation(Set.class);
|
||||
public static final TypeInformation<Map> MAP = new ClassTypeInformation(Map.class);
|
||||
public static final TypeInformation<Object> OBJECT = new ClassTypeInformation(Object.class);
|
||||
|
||||
private static final Map<Class<?>, Reference<TypeInformation<?>>> CACHE = Collections
|
||||
.synchronizedMap(new WeakHashMap<Class<?>, Reference<TypeInformation<?>>>());
|
||||
|
||||
static {
|
||||
for (TypeInformation<?> info : Arrays.asList(COLLECTION, LIST, SET, MAP, OBJECT)) {
|
||||
CACHE.put(info.getType(), new WeakReference<TypeInformation<?>>(info));
|
||||
}
|
||||
}
|
||||
|
||||
private final Class<S> type;
|
||||
|
||||
/**
|
||||
* Simple factory method to easily create new instances of {@link ClassTypeInformation}.
|
||||
*
|
||||
* @param <S>
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public static <S> TypeInformation<S> from(Class<S> type) {
|
||||
|
||||
Reference<TypeInformation<?>> cachedReference = CACHE.get(type);
|
||||
TypeInformation<?> cachedTypeInfo = cachedReference == null ? null : cachedReference.get();
|
||||
|
||||
if (cachedTypeInfo != null) {
|
||||
return (TypeInformation<S>) cachedTypeInfo;
|
||||
}
|
||||
|
||||
TypeInformation<S> result = new ClassTypeInformation<S>(type);
|
||||
CACHE.put(type, new WeakReference<TypeInformation<?>>(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TypeInformation} from the given method's return type.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
*/
|
||||
public static <S> TypeInformation<S> fromReturnTypeOf(Method method) {
|
||||
return new ClassTypeInformation(method.getDeclaringClass()).createInfo(method.getGenericReturnType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link ClassTypeInformation} for the given type.
|
||||
*
|
||||
* @param type
|
||||
*/
|
||||
ClassTypeInformation(Class<S> type) {
|
||||
this(type, GenericTypeResolver.getTypeVariableMap(type));
|
||||
}
|
||||
|
||||
ClassTypeInformation(Class<S> type, Map<TypeVariable, Type> typeVariableMap) {
|
||||
super(ClassUtils.getUserClass(type), typeVariableMap);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#getType()
|
||||
*/
|
||||
@Override
|
||||
public Class<S> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#isAssignableFrom(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Override
|
||||
public boolean isAssignableFrom(TypeInformation<?> target) {
|
||||
return getType().isAssignableFrom(target.getType());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Special {@link TypeDiscoverer} handling {@link GenericArrayType}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class GenericArrayTypeInformation<S> extends ParentTypeAwareTypeInformation<S> {
|
||||
|
||||
private GenericArrayType type;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GenericArrayTypeInformation} for the given {@link GenericArrayTypeInformation} and
|
||||
* {@link TypeDiscoverer}.
|
||||
*
|
||||
* @param type
|
||||
* @param parent
|
||||
*/
|
||||
protected GenericArrayTypeInformation(GenericArrayType type, TypeDiscoverer<?> parent) {
|
||||
super(type, parent, parent.getTypeVariableMap());
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#getType()
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<S> getType() {
|
||||
|
||||
return (Class<S>) Array.newInstance(resolveType(type.getGenericComponentType()), 0).getClass();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#getComponentType()
|
||||
*/
|
||||
@Override
|
||||
public TypeInformation<?> getComponentType() {
|
||||
|
||||
Type componentType = type.getGenericComponentType();
|
||||
return createInfo(componentType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
|
||||
|
||||
private final ParameterizedType type;
|
||||
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
public ParameterizedTypeInformation(ParameterizedType type, TypeDiscoverer<?> parent) {
|
||||
super(type, parent, null);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#getMapValueType()
|
||||
*/
|
||||
@Override
|
||||
public TypeInformation<?> getMapValueType() {
|
||||
|
||||
if (Map.class.equals(getType())) {
|
||||
Type[] arguments = type.getActualTypeArguments();
|
||||
return createInfo(arguments[1]);
|
||||
}
|
||||
|
||||
Class<?> rawType = getType();
|
||||
|
||||
Set<Type> supertypes = new HashSet<Type>();
|
||||
supertypes.add(rawType.getGenericSuperclass());
|
||||
supertypes.addAll(Arrays.asList(rawType.getGenericInterfaces()));
|
||||
|
||||
for (Type supertype : supertypes) {
|
||||
Class<?> rawSuperType = GenericTypeResolver.resolveType(supertype, getTypeVariableMap());
|
||||
if (Map.class.isAssignableFrom(rawSuperType)) {
|
||||
ParameterizedType parameterizedSupertype = (ParameterizedType) supertype;
|
||||
Type[] arguments = parameterizedSupertype.getActualTypeArguments();
|
||||
return createInfo(arguments[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return super.getMapValueType();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#getTypeParameters()
|
||||
*/
|
||||
@Override
|
||||
public List<TypeInformation<?>> getTypeArguments() {
|
||||
|
||||
List<TypeInformation<?>> result = new ArrayList<TypeInformation<?>>();
|
||||
|
||||
for (Type argument : type.getActualTypeArguments()) {
|
||||
result.add(createInfo(argument));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#isAssignableFrom(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Override
|
||||
public boolean isAssignableFrom(TypeInformation<?> target) {
|
||||
|
||||
if (this.equals(target)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Class<T> rawType = getType();
|
||||
Class<?> rawTargetType = target.getType();
|
||||
|
||||
if (!rawType.isAssignableFrom(rawTargetType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeInformation<?> otherTypeInformation = rawType.equals(rawTargetType) ? target : target
|
||||
.getSuperTypeInformation(rawType);
|
||||
|
||||
List<TypeInformation<?>> myParameters = getTypeArguments();
|
||||
List<TypeInformation<?>> typeParameters = otherTypeInformation.getTypeArguments();
|
||||
|
||||
if (myParameters.size() != typeParameters.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < myParameters.size(); i++) {
|
||||
if (!myParameters.get(i).isAssignableFrom(typeParameters.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#getComponentType()
|
||||
*/
|
||||
@Override
|
||||
public TypeInformation<?> getComponentType() {
|
||||
return createInfo(type.getActualTypeArguments()[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.ParentTypeAwareTypeInformation#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof ParameterizedTypeInformation)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ParameterizedTypeInformation<?> that = (ParameterizedTypeInformation<?>) obj;
|
||||
|
||||
if (this.isResolvedCompletely() && that.isResolvedCompletely()) {
|
||||
return this.type.equals(that.type);
|
||||
}
|
||||
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
private boolean isResolvedCompletely() {
|
||||
|
||||
Type[] types = type.getActualTypeArguments();
|
||||
|
||||
if (types.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Type type : types) {
|
||||
|
||||
TypeInformation<?> info = createInfo(type);
|
||||
|
||||
if (info instanceof ParameterizedTypeInformation) {
|
||||
if (!((ParameterizedTypeInformation<?>) info).isResolvedCompletely()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(info instanceof ClassTypeInformation)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Base class for {@link TypeInformation} implementations that need parent type awareness.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public abstract class ParentTypeAwareTypeInformation<S> extends TypeDiscoverer<S> {
|
||||
|
||||
private final TypeDiscoverer<?> parent;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ParentTypeAwareTypeInformation}.
|
||||
*
|
||||
* @param type
|
||||
* @param parent
|
||||
* @param map
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected ParentTypeAwareTypeInformation(Type type, TypeDiscoverer<?> parent, Map<TypeVariable, Type> map) {
|
||||
super(type, map);
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers the parent's type variable map before invoking the super class method.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected Map<TypeVariable, Type> getTypeVariableMap() {
|
||||
return parent == null ? super.getTypeVariableMap() : parent.getTypeVariableMap();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#createInfo(java.lang.reflect.Type)
|
||||
*/
|
||||
@Override
|
||||
protected TypeInformation<?> createInfo(Type fieldType) {
|
||||
|
||||
if (parent.getType().equals(fieldType)) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
return super.createInfo(fieldType);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ParentTypeAwareTypeInformation<?> that = (ParentTypeAwareTypeInformation<?>) obj;
|
||||
return this.parent == null ? that.parent == null : this.parent.equals(that.parent);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode() + 31 * ObjectUtils.nullSafeHashCode(parent);
|
||||
}
|
||||
}
|
||||
174
src/main/java/org/springframework/data/util/ReflectionUtils.java
Normal file
174
src/main/java/org/springframework/data/util/ReflectionUtils.java
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2012 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils.FieldFilter;
|
||||
|
||||
/**
|
||||
* Spring Data specific reflection utility methods and classes.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public class ReflectionUtils {
|
||||
|
||||
/**
|
||||
* A {@link FieldFilter} that has a description.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface DescribedFieldFilter extends FieldFilter {
|
||||
|
||||
/**
|
||||
* Returns the description of the field filter. Used in exceptions being thrown in case uniqueness shall be enforced
|
||||
* on the field filter.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link FieldFilter} for a given annotation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public static class AnnotationFieldFilter implements DescribedFieldFilter {
|
||||
|
||||
private final Class<? extends Annotation> annotationType;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationFieldFilter} for the given annotation type.
|
||||
*/
|
||||
public AnnotationFieldFilter(Class<? extends Annotation> annotationType) {
|
||||
|
||||
Assert.notNull(annotationType, "Annotation type must not be null!");
|
||||
this.annotationType = annotationType;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.util.ReflectionUtils.FieldFilter#matches(java.lang.reflect.Field)
|
||||
*/
|
||||
public boolean matches(Field field) {
|
||||
return AnnotationUtils.getAnnotation(field, annotationType) != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.ReflectionUtils.DescribedFieldFilter#getDescription()
|
||||
*/
|
||||
public String getDescription() {
|
||||
return String.format("Annotation filter for %s", annotationType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first field on the given class matching the given {@link FieldFilter}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param filter must not be {@literal null}.
|
||||
* @return the field matching the filter or {@literal null} in case no field could be found.
|
||||
*/
|
||||
public static Field findField(Class<?> type, final FieldFilter filter) {
|
||||
|
||||
return findField(type, new DescribedFieldFilter() {
|
||||
|
||||
public boolean matches(Field field) {
|
||||
return filter.matches(field);
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return String.format("FieldFilter %s", filter.toString());
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the field matching the given {@link DescribedFieldFilter}. Will make sure there's only one field matching the
|
||||
* filter.
|
||||
*
|
||||
* @see #findField(Class, DescribedFieldFilter, boolean)
|
||||
* @param type must not be {@literal null}.
|
||||
* @param filter must not be {@literal null}.
|
||||
* @return the field matching the given {@link DescribedFieldFilter} or {@literal null} if none found.
|
||||
* @throws IllegalStateException in case more than one matching field is found
|
||||
*/
|
||||
public static Field findField(Class<?> type, DescribedFieldFilter filter) {
|
||||
return findField(type, filter, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the field matching the given {@link DescribedFieldFilter}. Will make sure there's only one field matching the
|
||||
* filter in case {@code enforceUniqueness} is {@literal true}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param filter must not be {@literal null}.
|
||||
* @param enforceUniqueness whether to enforce uniqueness of the field
|
||||
* @return the field matching the given {@link DescribedFieldFilter} or {@literal null} if none found.
|
||||
* @throws IllegalStateException if enforceUniqueness is true and more than one matching field is found
|
||||
*/
|
||||
public static Field findField(Class<?> type, DescribedFieldFilter filter, boolean enforceUniqueness) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
Assert.notNull(filter, "Filter must not be null!");
|
||||
|
||||
Class<?> targetClass = type;
|
||||
Field foundField = null;
|
||||
|
||||
while (targetClass != Object.class) {
|
||||
|
||||
for (Field field : targetClass.getDeclaredFields()) {
|
||||
|
||||
if (!filter.matches(field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!enforceUniqueness) {
|
||||
return field;
|
||||
}
|
||||
|
||||
if (foundField != null && enforceUniqueness) {
|
||||
throw new IllegalStateException(filter.getDescription());
|
||||
}
|
||||
|
||||
foundField = field;
|
||||
}
|
||||
|
||||
targetClass = targetClass.getSuperclass();
|
||||
}
|
||||
|
||||
return foundField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given field on the given object to the given value. Will make sure the given field is accessible.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
* @param target must not be {@literal null}.
|
||||
* @param value
|
||||
*/
|
||||
public static void setField(Field field, Object target, Object value) {
|
||||
|
||||
org.springframework.util.ReflectionUtils.makeAccessible(field);
|
||||
org.springframework.util.ReflectionUtils.setField(field, target, value);
|
||||
}
|
||||
}
|
||||
460
src/main/java/org/springframework/data/util/TypeDiscoverer.java
Normal file
460
src/main/java/org/springframework/data/util/TypeDiscoverer.java
Normal file
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
* Copyright 2011-2012 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import static org.springframework.util.ObjectUtils.*;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Basic {@link TypeDiscoverer} that contains basic functionality to discover property types.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
private final Type type;
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final Map<TypeVariable, Type> typeVariableMap;
|
||||
private final Map<String, TypeInformation<?>> fieldTypes = new ConcurrentHashMap<String, TypeInformation<?>>();
|
||||
|
||||
/**
|
||||
* Creates a ne {@link TypeDiscoverer} for the given type, type variable map and parent.
|
||||
*
|
||||
* @param type must not be null.
|
||||
* @param typeVariableMap
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected TypeDiscoverer(Type type, Map<TypeVariable, Type> typeVariableMap) {
|
||||
|
||||
Assert.notNull(type);
|
||||
this.type = type;
|
||||
this.typeVariableMap = typeVariableMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type variable map. Will traverse the parents up to the root on and use it's map.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected Map<TypeVariable, Type> getTypeVariableMap() {
|
||||
|
||||
return typeVariableMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link TypeInformation} for the given {@link Type}.
|
||||
*
|
||||
* @param fieldType
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
protected TypeInformation<?> createInfo(Type fieldType) {
|
||||
|
||||
if (fieldType.equals(this.type)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (fieldType instanceof Class) {
|
||||
return new ClassTypeInformation((Class<?>) fieldType);
|
||||
}
|
||||
|
||||
Map<TypeVariable, Type> variableMap = GenericTypeResolver.getTypeVariableMap(resolveType(fieldType));
|
||||
|
||||
if (fieldType instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) fieldType;
|
||||
return new ParameterizedTypeInformation(parameterizedType, this);
|
||||
}
|
||||
|
||||
if (fieldType instanceof TypeVariable) {
|
||||
TypeVariable<?> variable = (TypeVariable<?>) fieldType;
|
||||
return new TypeVariableTypeInformation(variable, type, this, variableMap);
|
||||
}
|
||||
|
||||
if (fieldType instanceof GenericArrayType) {
|
||||
return new GenericArrayTypeInformation((GenericArrayType) fieldType, this);
|
||||
}
|
||||
|
||||
if (fieldType instanceof WildcardType) {
|
||||
|
||||
WildcardType wildcardType = (WildcardType) fieldType;
|
||||
Type[] bounds = wildcardType.getLowerBounds();
|
||||
|
||||
if (bounds.length > 0) {
|
||||
return createInfo(bounds[0]);
|
||||
}
|
||||
|
||||
bounds = wildcardType.getUpperBounds();
|
||||
|
||||
if (bounds.length > 0) {
|
||||
return createInfo(bounds[0]);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given type into a plain {@link Class}.
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Class<S> resolveType(Type type) {
|
||||
|
||||
return (Class<S>) GenericTypeResolver.resolveType(type, getTypeVariableMap());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getParameterTypes(java.lang.reflect.Constructor)
|
||||
*/
|
||||
public List<TypeInformation<?>> getParameterTypes(Constructor<?> constructor) {
|
||||
|
||||
Assert.notNull(constructor);
|
||||
List<TypeInformation<?>> result = new ArrayList<TypeInformation<?>>();
|
||||
|
||||
for (Type type : constructor.getGenericParameterTypes()) {
|
||||
result.add(createInfo(type));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getProperty(java.lang.String)
|
||||
*/
|
||||
public TypeInformation<?> getProperty(String fieldname) {
|
||||
|
||||
int separatorIndex = fieldname.indexOf('.');
|
||||
|
||||
if (separatorIndex == -1) {
|
||||
if (fieldTypes.containsKey(fieldname)) {
|
||||
return fieldTypes.get(fieldname);
|
||||
}
|
||||
|
||||
TypeInformation<?> propertyInformation = getPropertyInformation(fieldname);
|
||||
if (propertyInformation != null) {
|
||||
fieldTypes.put(fieldname, propertyInformation);
|
||||
}
|
||||
return propertyInformation;
|
||||
}
|
||||
|
||||
String head = fieldname.substring(0, separatorIndex);
|
||||
TypeInformation<?> info = fieldTypes.get(head);
|
||||
return info == null ? null : info.getProperty(fieldname.substring(separatorIndex + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} for the given atomic field. Will inspect fields first and return the type of a
|
||||
* field if available. Otherwise it will fall back to a {@link PropertyDescriptor}.
|
||||
*
|
||||
* @see #getGenericType(PropertyDescriptor)
|
||||
* @param fieldname
|
||||
* @return
|
||||
*/
|
||||
private TypeInformation<?> getPropertyInformation(String fieldname) {
|
||||
|
||||
Class<?> type = getType();
|
||||
Field field = ReflectionUtils.findField(type, fieldname);
|
||||
|
||||
if (field != null) {
|
||||
return createInfo(field.getGenericType());
|
||||
}
|
||||
|
||||
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(type, fieldname);
|
||||
|
||||
return descriptor == null ? null : createInfo(getGenericType(descriptor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the generic type for the given {@link PropertyDescriptor}. Will inspect its read method followed by the
|
||||
* first parameter of the write method.
|
||||
*
|
||||
* @param descriptor must not be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
private static Type getGenericType(PropertyDescriptor descriptor) {
|
||||
|
||||
Method method = descriptor.getReadMethod();
|
||||
|
||||
if (method != null) {
|
||||
return method.getGenericReturnType();
|
||||
}
|
||||
|
||||
method = descriptor.getWriteMethod();
|
||||
|
||||
if (method == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type[] parameterTypes = method.getGenericParameterTypes();
|
||||
return parameterTypes.length == 0 ? null : parameterTypes[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getType()
|
||||
*/
|
||||
public Class<S> getType() {
|
||||
return resolveType(type);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getActualType()
|
||||
*/
|
||||
public TypeInformation<?> getActualType() {
|
||||
|
||||
if (isMap()) {
|
||||
return getMapValueType();
|
||||
}
|
||||
|
||||
if (isCollectionLike()) {
|
||||
return getComponentType();
|
||||
}
|
||||
|
||||
List<TypeInformation<?>> arguments = getTypeArguments();
|
||||
|
||||
if (arguments.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return arguments.get(arguments.size() - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#isMap()
|
||||
*/
|
||||
public boolean isMap() {
|
||||
return Map.class.isAssignableFrom(getType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getMapValueType()
|
||||
*/
|
||||
public TypeInformation<?> getMapValueType() {
|
||||
|
||||
if (isMap()) {
|
||||
return getTypeArgument(getType(), Map.class, 1);
|
||||
}
|
||||
|
||||
List<TypeInformation<?>> arguments = getTypeArguments();
|
||||
|
||||
if (arguments.size() > 1) {
|
||||
return arguments.get(1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#isCollectionLike()
|
||||
*/
|
||||
public boolean isCollectionLike() {
|
||||
|
||||
Class<?> rawType = getType();
|
||||
|
||||
if (rawType.isArray() || Iterable.class.equals(rawType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Collection.class.isAssignableFrom(rawType);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getComponentType()
|
||||
*/
|
||||
public TypeInformation<?> getComponentType() {
|
||||
|
||||
Class<S> rawType = getType();
|
||||
|
||||
if (rawType.isArray()) {
|
||||
return createInfo(rawType.getComponentType());
|
||||
}
|
||||
|
||||
if (isMap()) {
|
||||
return getTypeArgument(rawType, Map.class, 0);
|
||||
}
|
||||
|
||||
if (Iterable.class.isAssignableFrom(rawType)) {
|
||||
return getTypeArgument(rawType, Iterable.class, 0);
|
||||
}
|
||||
|
||||
List<TypeInformation<?>> arguments = getTypeArguments();
|
||||
|
||||
if (arguments.size() > 0) {
|
||||
return arguments.get(0);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getReturnType(java.lang.reflect.Method)
|
||||
*/
|
||||
public TypeInformation<?> getReturnType(Method method) {
|
||||
|
||||
Assert.notNull(method);
|
||||
return createInfo(method.getGenericReturnType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getMethodParameterTypes(java.lang.reflect.Method)
|
||||
*/
|
||||
public List<TypeInformation<?>> getParameterTypes(Method method) {
|
||||
|
||||
Assert.notNull(method);
|
||||
|
||||
Type[] parameterTypes = method.getGenericParameterTypes();
|
||||
List<TypeInformation<?>> result = new ArrayList<TypeInformation<?>>(parameterTypes.length);
|
||||
|
||||
for (Type type : parameterTypes) {
|
||||
result.add(createInfo(type));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getSuperTypeInformation(java.lang.Class)
|
||||
*/
|
||||
public TypeInformation<?> getSuperTypeInformation(Class<?> superType) {
|
||||
|
||||
Class<?> type = getType();
|
||||
|
||||
if (!superType.isAssignableFrom(type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (getType().equals(superType)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
List<Type> candidates = new ArrayList<Type>();
|
||||
|
||||
Type genericSuperclass = type.getGenericSuperclass();
|
||||
if (genericSuperclass != null) {
|
||||
candidates.add(genericSuperclass);
|
||||
}
|
||||
candidates.addAll(Arrays.asList(type.getGenericInterfaces()));
|
||||
|
||||
for (Type candidate : candidates) {
|
||||
|
||||
TypeInformation<?> candidateInfo = createInfo(candidate);
|
||||
|
||||
if (superType.equals(candidateInfo.getType())) {
|
||||
return candidateInfo;
|
||||
} else {
|
||||
TypeInformation<?> nestedSuperType = candidateInfo.getSuperTypeInformation(superType);
|
||||
if (nestedSuperType != null) {
|
||||
return nestedSuperType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#getTypeParameters()
|
||||
*/
|
||||
public List<TypeInformation<?>> getTypeArguments() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeInformation#isAssignableFrom(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
public boolean isAssignableFrom(TypeInformation<?> target) {
|
||||
return target.getSuperTypeInformation(getType()).equals(this);
|
||||
}
|
||||
|
||||
private TypeInformation<?> getTypeArgument(Class<?> type, Class<?> bound, int index) {
|
||||
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(type, bound);
|
||||
return arguments == null ? null : createInfo(arguments[index]);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeDiscoverer<?> that = (TypeDiscoverer<?>) obj;
|
||||
|
||||
boolean typeEqual = nullSafeEquals(this.type, that.type);
|
||||
boolean typeVariableMapEqual = nullSafeEquals(this.typeVariableMap, that.typeVariableMap);
|
||||
|
||||
return typeEqual && typeVariableMapEqual;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
result += nullSafeHashCode(type);
|
||||
result += nullSafeHashCode(typeVariableMap);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
135
src/main/java/org/springframework/data/util/TypeInformation.java
Normal file
135
src/main/java/org/springframework/data/util/TypeInformation.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2008-2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface to access property types and resolving generics on the way. Starting with a {@link ClassTypeInformation}
|
||||
* you can travers properties using {@link #getProperty(String)} to access type information.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
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
|
||||
*/
|
||||
List<TypeInformation<?>> getParameterTypes(Constructor<?> constructor);
|
||||
|
||||
/**
|
||||
* Returns the property information for the property with the given name. Supports proeprty traversal through dot
|
||||
* notation.
|
||||
*
|
||||
* @param fieldname
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<?> getProperty(String fieldname);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
TypeInformation<?> getComponentType();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
TypeInformation<?> getMapValueType();
|
||||
|
||||
/**
|
||||
* Returns the type of the property. Will resolve generics and the generic context of
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Class<S> getType();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
TypeInformation<?> getReturnType(Method method);
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation}s for the parameters of the given {@link Method}.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
List<TypeInformation<?>> getParameterTypes(Method method);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
TypeInformation<?> getSuperTypeInformation(Class<?> superType);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
boolean isAssignableFrom(TypeInformation<?> target);
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} for the type arguments of the current {@link TypeInformation}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<TypeInformation<?>> getTypeArguments();
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import static org.springframework.util.ObjectUtils.*;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Special {@link TypeDiscoverer} to determine the actual type for a {@link TypeVariable}. Will consider the context the
|
||||
* {@link TypeVariable} is being used in.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class TypeVariableTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
|
||||
|
||||
private final TypeVariable<?> variable;
|
||||
private final Type owningType;
|
||||
|
||||
/**
|
||||
* Creates a bew {@link TypeVariableTypeInformation} for the given {@link TypeVariable} owning {@link Type} and parent
|
||||
* {@link TypeDiscoverer}.
|
||||
*
|
||||
* @param variable must not be {@literal null}
|
||||
* @param owningType must not be {@literal null}
|
||||
* @param parent
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public TypeVariableTypeInformation(TypeVariable<?> variable, Type owningType, TypeDiscoverer<?> parent,
|
||||
Map<TypeVariable, Type> map) {
|
||||
|
||||
super(variable, parent, map);
|
||||
Assert.notNull(variable);
|
||||
this.variable = variable;
|
||||
this.owningType = owningType;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.document.mongodb.TypeDiscovererTest.TypeDiscoverer#getType()
|
||||
*/
|
||||
@Override
|
||||
public Class<T> getType() {
|
||||
|
||||
int index = getIndex(variable);
|
||||
|
||||
if (owningType instanceof ParameterizedType && index != -1) {
|
||||
Type fieldType = ((ParameterizedType) owningType).getActualTypeArguments()[index];
|
||||
return resolveType(fieldType);
|
||||
}
|
||||
|
||||
return resolveType(variable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the type parameter binding the given {@link TypeVariable}.
|
||||
*
|
||||
* @param variable
|
||||
* @return
|
||||
*/
|
||||
private int getIndex(TypeVariable<?> variable) {
|
||||
|
||||
Class<?> rawType = resolveType(owningType);
|
||||
TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
|
||||
|
||||
for (int i = 0; i < typeParameters.length; i++) {
|
||||
if (variable.equals(typeParameters[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.util.TypeDiscoverer#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeVariableTypeInformation<?> that = (TypeVariableTypeInformation<?>) obj;
|
||||
return nullSafeEquals(this.owningType, that.owningType) && nullSafeEquals(this.variable, that.variable);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.util.TypeDiscoverer#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result += 31 * nullSafeHashCode(this.owningType);
|
||||
result += 31 * nullSafeHashCode(this.variable);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Core utility APIs such as a type information framework to resolve generic types.
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
Reference in New Issue
Block a user