Skip to content

Commit

Permalink
HV-783 Extracting logic dealing with class hierarchies into dedicated…
Browse files Browse the repository at this point in the history
… class ClassHierarchyHelper
  • Loading branch information
gunnarmorling committed Mar 27, 2013
1 parent 53804f9 commit 3f5a84b
Show file tree
Hide file tree
Showing 11 changed files with 271 additions and 200 deletions.
Expand Up @@ -58,6 +58,7 @@
import org.hibernate.validator.internal.cdi.interceptor.ValidationInterceptor;
import org.hibernate.validator.internal.util.Contracts;
import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.classhierarchy.ClassHierarchyHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;

Expand Down Expand Up @@ -205,7 +206,7 @@ private <T> Set<AnnotatedCallable<? super T>> determineConstrainedCallables(Anno
private <T> void determineConstrainedMethod(AnnotatedType<T> type,
BeanDescriptor beanDescriptor,
Set<AnnotatedCallable<? super T>> callables) {
List<Method> overriddenAndImplementedMethods = ReflectionHelper.computeAllMethods( type.getJavaClass() );
List<Method> overriddenAndImplementedMethods = ClassHierarchyHelper.getAllMethods( type.getJavaClass() );
for ( AnnotatedMethod<? super T> annotatedMethod : type.getMethods() ) {
Method method = annotatedMethod.getJavaMember();

Expand Down Expand Up @@ -241,7 +242,7 @@ private <T> void determineConstrainedMethod(AnnotatedType<T> type,
private <T> void determineConstrainedConstructors(AnnotatedType<T> type, BeanDescriptor beanDescriptor, EnumSet<ExecutableType> classLevelExecutableTypes, Set<AnnotatedCallable<? super T>> callables) {
// no special inheritance rules to consider for constructors
for ( AnnotatedConstructor<T> annotatedConstructor : type.getConstructors() ) {
Constructor constructor = annotatedConstructor.getJavaMember();
Constructor<?> constructor = annotatedConstructor.getJavaMember();
EnumSet<ExecutableType> memberLevelExecutableType = executableTypesDefinedOnConstructor( constructor );

if ( veto( classLevelExecutableTypes, memberLevelExecutableType, ExecutableType.CONSTRUCTORS ) ) {
Expand Down Expand Up @@ -335,8 +336,8 @@ private EnumSet<ExecutableType> executableTypesDefinedOnMethod(Method method, bo
return executableTypes;
}

private EnumSet<ExecutableType> executableTypesDefinedOnConstructor(Constructor constructor) {
ValidateOnExecution validateOnExecutionAnnotation = (ValidateOnExecution) constructor.getAnnotation(
private EnumSet<ExecutableType> executableTypesDefinedOnConstructor(Constructor<?> constructor) {
ValidateOnExecution validateOnExecutionAnnotation = constructor.getAnnotation(
ValidateOnExecution.class
);
EnumSet<ExecutableType> executableTypes = commonExecutableTypeChecks( validateOnExecutionAnnotation );
Expand Down
Expand Up @@ -45,8 +45,8 @@
import org.hibernate.validator.internal.metadata.raw.ConstrainedType;
import org.hibernate.validator.internal.metadata.raw.ExecutableElement;
import org.hibernate.validator.internal.util.CollectionHelper.Partitioner;
import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.classfilter.ClassFilters;
import org.hibernate.validator.internal.util.classhierarchy.ClassHierarchyHelper;
import org.hibernate.validator.internal.util.classhierarchy.Filters;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;
Expand All @@ -55,7 +55,6 @@
import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap;
import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;
import static org.hibernate.validator.internal.util.CollectionHelper.partition;
import static org.hibernate.validator.internal.util.ReflectionHelper.computeAllImplementedInterfaces;

/**
* This class encapsulates all meta data needed for validation. Implementations of {@code Validator} interface can
Expand Down Expand Up @@ -170,14 +169,14 @@ public BeanMetaDataImpl(Class<T> beanClass,
this.cascadedProperties = Collections.unmodifiableSet( cascadedProperties );
this.allMetaConstraints = Collections.unmodifiableSet( allMetaConstraints );

this.classHierarchyWithoutInterfaces = ReflectionHelper.computeClassHierarchy(
this.classHierarchyWithoutInterfaces = ClassHierarchyHelper.getHierarchy(
beanClass,
ClassFilters.excludingInterfaces()
Filters.excludeInterfaces()
);

setDefaultGroupSequenceOrProvider( defaultGroupSequence, defaultGroupSequenceProvider );

this.directMetaConstraints = buildDirectConstraintSets();
this.directMetaConstraints = getDirectConstraints();

this.executableMetaDataMap = Collections.unmodifiableMap( byIdentifier( executableMetaDataSet ) );

Expand Down Expand Up @@ -339,11 +338,12 @@ private Set<MetaConstraint<?>> getClassLevelConstraints(Set<MetaConstraint<?>> c
return classLevelConstraints != null ? classLevelConstraints : Collections.<MetaConstraint<?>>emptySet();
}

private Set<MetaConstraint<?>> buildDirectConstraintSets() {
private Set<MetaConstraint<?>> getDirectConstraints() {
Set<MetaConstraint<?>> constraints = newHashSet();

Set<Class<?>> classAndInterfaces = computeAllImplementedInterfaces( beanClass );
Set<Class<?>> classAndInterfaces = newHashSet();
classAndInterfaces.add( beanClass );
classAndInterfaces.addAll( ClassHierarchyHelper.getDirectlyImplementedInterfaces( beanClass ) );

for ( Class<?> clazz : classAndInterfaces ) {
for ( MetaConstraint<?> metaConstraint : allMetaConstraints ) {
Expand Down
Expand Up @@ -56,6 +56,7 @@
import org.hibernate.validator.internal.util.CollectionHelper.Partitioner;
import org.hibernate.validator.internal.util.ConcurrentReferenceHashMap;
import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.classhierarchy.ClassHierarchyHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;
Expand Down Expand Up @@ -108,7 +109,7 @@ public AnnotationProcessingOptions getAnnotationProcessingOptions() {
public <T> List<BeanConfiguration<? super T>> getBeanConfigurationForHierarchy(Class<T> beanClass) {
List<BeanConfiguration<? super T>> configurations = newArrayList();

for ( Class<? super T> hierarchyClass : ReflectionHelper.computeClassHierarchy( beanClass ) ) {
for ( Class<? super T> hierarchyClass : ClassHierarchyHelper.getHierarchy( beanClass ) ) {
BeanConfiguration<? super T> configuration = getBeanConfiguration( hierarchyClass );
if ( configuration != null ) {
configurations.add( configuration );
Expand Down
Expand Up @@ -25,7 +25,7 @@
import org.hibernate.validator.internal.metadata.raw.ConfigurationSource;
import org.hibernate.validator.internal.metadata.raw.ConstrainedElement;
import org.hibernate.validator.internal.util.Contracts;
import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.classhierarchy.ClassHierarchyHelper;
import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;

import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList;
Expand All @@ -51,7 +51,7 @@ public MetaDataProviderKeyedByClassName(ConstraintHelper constraintHelper) {
public <T> List<BeanConfiguration<? super T>> getBeanConfigurationForHierarchy(Class<T> beanClass) {
List<BeanConfiguration<? super T>> configurations = newArrayList();

for ( Class<? super T> clazz : ReflectionHelper.computeClassHierarchy( beanClass ) ) {
for ( Class<? super T> clazz : ClassHierarchyHelper.getHierarchy( beanClass ) ) {
BeanConfiguration<? super T> configuration = getBeanConfiguration( clazz );
if ( configuration != null ) {
configurations.add( configuration );
Expand Down
Expand Up @@ -35,7 +35,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.fasterxml.classmate.Filter;
import com.fasterxml.classmate.MemberResolver;
Expand All @@ -46,8 +45,6 @@
import com.fasterxml.classmate.members.ResolvedMethod;

import org.hibernate.validator.internal.metadata.raw.ExecutableElement;
import org.hibernate.validator.internal.util.classfilter.ClassFilter;
import org.hibernate.validator.internal.util.classfilter.ClassFilters;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.hibernate.validator.internal.util.privilegedactions.ConstructorInstance;
Expand All @@ -66,9 +63,7 @@
import org.hibernate.validator.internal.util.privilegedactions.NewInstance;
import org.hibernate.validator.internal.util.privilegedactions.SetAccessibility;

import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList;
import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap;
import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;
import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;

/**
Expand Down Expand Up @@ -699,97 +694,6 @@ public static Class<?> unBoxedType(Class<?> type) {
return wrapperType;
}

/**
* Get all superclasses and optionally interfaces recursively. Classed are added by starting with the specified
* class and its implemented interfaces. Then the super class of {@code clazz} is added and its interfaces and so on.
*
* @param clazz the class to start the search with
* @param filters filters applying for the search
*
* @return List of super types of {@code clazz}. Will only contain those
* super types matching the given filters. The list contains the
* given class itself, if it is no proxy class. An empty list is
* returned if {@code clazz} is {@code null}.
*/
public static <T> List<Class<? super T>> computeClassHierarchy(Class<T> clazz, ClassFilter... filters) {
List<Class<? super T>> classes = newArrayList();

List<ClassFilter> allFilters = newArrayList();
allFilters.addAll( Arrays.asList( filters ) );
allFilters.add( ClassFilters.excludingProxies() );

computeClassHierarchy( clazz, classes, allFilters );
return classes;
}

/**
* Get all superclasses and interfaces recursively.
*
* @param clazz the class to start the search with
* @param classes list of classes to which to add all found super types matching the given filters
* @param filters filters applying for the search
*/
private static <T> void computeClassHierarchy(Class<? super T> clazz, List<Class<? super T>> classes, Iterable<ClassFilter> filters) {
for ( Class<? super T> current = clazz; current != null; current = current.getSuperclass() ) {
if ( classes.contains( current ) ) {
return;
}

if ( acceptedByAllFilters( current, filters ) ) {
classes.add( current );
}

for ( Class<?> currentInterface : current.getInterfaces() ) {
@SuppressWarnings("unchecked") //safe since interfaces are super-types
Class<? super T> currentInterfaceCasted = (Class<? super T>) currentInterface;
computeClassHierarchy( currentInterfaceCasted, classes, filters );
}
}
}

private static boolean acceptedByAllFilters(Class<?> clazz, Iterable<ClassFilter> filters) {
for ( ClassFilter classFilter : filters ) {
if ( !classFilter.accepts( clazz ) ) {
return false;
}
}

return true;
}

/**
* Get a list of all methods a class declares, implements, overrides or inherits. Methods are added by adding
* first all methods of the class itself and its implementing interfaces , then the super class and its interfaces, etc.
*
* @param clazz The class for which to find all methods.
*
* @return returns set of all methods of {@code clazz}. The empty list is returned if {@code clazz} is {@code null}
*/
public static <T> List<Method> computeAllMethods(Class<T> clazz) {
List<Method> methods = newArrayList();

List<Class<? super T>> hierarchyClasses = computeClassHierarchy( clazz );
for ( Class<?> hierarchyClass : hierarchyClasses ) {
Collections.addAll( methods, getMethods( hierarchyClass ) );
}

return methods;
}

/**
* Get all interfaces a class directly implements.
*
* @param clazz The class for which to find the interfaces
*
* @return Set of all interfaces {@code clazz} implements. The empty list is returned if {@code clazz} does not
* implement any interfaces or {@code clazz} is {@code null}.
*/
public static Set<Class<?>> computeAllImplementedInterfaces(Class<?> clazz) {
Set<Class<?>> classes = newHashSet();
computeAllImplementedInterfaces( clazz, classes );
return classes;
}

/**
* Checks, whether {@code subTypeMethod} overrides {@code superTypeMethod}.
*
Expand Down Expand Up @@ -859,16 +763,6 @@ private static boolean parametersResolveToSameTypes(Method subTypeMethod, Method
return true;
}

private static void computeAllImplementedInterfaces(Class<?> clazz, Set<Class<?>> classes) {
if ( clazz == null ) {
return;
}
for ( Class<?> currentInterface : clazz.getInterfaces() ) {
classes.add( currentInterface );
computeAllImplementedInterfaces( currentInterface, classes );
}
}

/**
* A filter implementation filtering methods matching given methods.
*
Expand Down

0 comments on commit 3f5a84b

Please sign in to comment.