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:
Oliver Gierke
2013-01-11 12:13:47 +01:00
parent c908d0e023
commit ac256f9921
375 changed files with 215 additions and 3092 deletions

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View 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);
}
}

View 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;
}
}

View 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();
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,4 @@
/**
* Core utility APIs such as a type information framework to resolve generic types.
*/
package org.springframework.data.util;