package com.google.inject; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * Will filter in or out classes based on the information gathered by the annotation * preprocessor of RoboGuice. A class is filtered in if it contains an injection point * or its super classes contain an injection point.<br/> * Once a class is filtered in has having injection points, * its super classes are kept as long as they satisfy the filtering operated * by {@link RoboGuiceHierarchyTraversalFilter}. Otherwise, the class will be rejected * by the filter. * @author SNI */ public class AnnotatedGuiceHierarchyTraversalFilter extends HierarchyTraversalFilter { private boolean hasHadInjectionPoints; private HashMap<String, Map<String, Set<String>>> mapAnnotationToMapClassWithInjectionNameToConstructorSet; private HashMap<String, Map<String, Set<String>>> mapAnnotationToMapClassWithInjectionNameToMethodSet; private HashMap<String, Map<String, Set<String>>> mapAnnotationToMapClassWithInjectionNameToFieldSet; private HashSet<String> classesContainingInjectionPointsSet = new HashSet<String>(); private HierarchyTraversalFilter delegate; public AnnotatedGuiceHierarchyTraversalFilter(AnnotationDatabaseFinder annotationDatabaseFinder, HierarchyTraversalFilter delegate ) { this.delegate = delegate; mapAnnotationToMapClassWithInjectionNameToFieldSet = annotationDatabaseFinder.getMapAnnotationToMapClassContainingInjectionToInjectedFieldSet(); mapAnnotationToMapClassWithInjectionNameToMethodSet = annotationDatabaseFinder.getMapAnnotationToMapClassContainingInjectionToInjectedMethodSet(); mapAnnotationToMapClassWithInjectionNameToConstructorSet = annotationDatabaseFinder.getMapAnnotationToMapClassContainingInjectionToInjectedConstructorSet(); classesContainingInjectionPointsSet = annotationDatabaseFinder.getClassesContainingInjectionPointsSet(); if(classesContainingInjectionPointsSet.isEmpty()) throw new IllegalStateException("Unable to find Annotation Database which should be output as part of annotation processing"); } @Override public void reset( ) { delegate.reset(); hasHadInjectionPoints = false; } @Override public boolean isWorthScanning(Class<?> c) { if( hasHadInjectionPoints ) { return delegate.isWorthScanning(c); } else if( c != null ) { do { if( classesContainingInjectionPointsSet.contains(c.getName()) ) { hasHadInjectionPoints = true; return true; } c = c.getSuperclass(); } while( delegate.isWorthScanning(c) ); } return false; } @Override public boolean isWorthScanningForFields(String annotationClassName, Class<?> c) { Map<String, Set<String>> classesContainingInjectionPointsForAnnotation; if( hasHadInjectionPoints ) { return delegate.isWorthScanning(c); } else if( c != null ) { classesContainingInjectionPointsForAnnotation = mapAnnotationToMapClassWithInjectionNameToFieldSet.get(annotationClassName); if( classesContainingInjectionPointsForAnnotation == null ) { return false; } do { if( classesContainingInjectionPointsForAnnotation.containsKey(c.getName()) ) { hasHadInjectionPoints = true; return true; } c = c.getSuperclass(); } while( delegate.isWorthScanning(c) ); } return false; } @Override public Set<Field> getAllFields(String annotationClassName, Class<?> c) { Map<String, Set<String>> classesContainingInjectionPointsForAnnotation = mapAnnotationToMapClassWithInjectionNameToFieldSet.get(annotationClassName); if( c != null && classesContainingInjectionPointsForAnnotation!= null ) { Set<String> fieldNameSet = classesContainingInjectionPointsForAnnotation.get(c.getName()); if( fieldNameSet != null ) { Set<Field> fieldSet = new HashSet<Field>(); try { for( String fieldName : fieldNameSet ) { fieldSet.add( c.getDeclaredField(fieldName)); } return fieldSet; } catch( Exception ex ) { ex.printStackTrace(); } } } //costly but should not happen return Collections.emptySet(); } @Override public boolean isWorthScanningForMethods(String annotationClassName, Class<?> c) { Map<String, Set<String>> classesContainingInjectionPointsForAnnotation; if( hasHadInjectionPoints ) { return delegate.isWorthScanning(c); } else if( c != null ) { classesContainingInjectionPointsForAnnotation = mapAnnotationToMapClassWithInjectionNameToMethodSet.get(annotationClassName); if( classesContainingInjectionPointsForAnnotation == null ) { return false; } do { if( classesContainingInjectionPointsForAnnotation.containsKey(c.getName()) ) { hasHadInjectionPoints = true; return true; } c = c.getSuperclass(); } while( delegate.isWorthScanning(c) ); } return false; } @Override public Set<Method> getAllMethods(String annotationClassName, Class<?> c) { //System.out.printf("map of methods : %s \n",mapAnnotationToMapClassWithInjectionNameToMethodSet.toString()); Map<String, Set<String>> classesContainingInjectionPointsForAnnotation = mapAnnotationToMapClassWithInjectionNameToMethodSet.get(annotationClassName); if( c != null && classesContainingInjectionPointsForAnnotation!= null ) { Set<String> methodNameSet = classesContainingInjectionPointsForAnnotation.get(c.getName()); if( methodNameSet != null ) { Set<Method> methodSet = new HashSet<Method>(); try { for( String methodNameAndParamClasses : methodNameSet ) { //System.out.printf("Getting method %s of class %s \n",methodNameAndParamClasses,c.getName()); String[] split = methodNameAndParamClasses.split(":"); String methodName = split[0]; Class<?>[] paramClass = new Class[split.length-1]; for( int i=1;i<split.length;i++) { paramClass[i-1] = getClass().getClassLoader().loadClass(split[i]); } methodSet.add( c.getDeclaredMethod(methodName, paramClass)); } return methodSet; } catch( Exception ex ) { ex.printStackTrace(); } } } //costly but should not happen return Collections.emptySet(); } @Override public boolean isWorthScanningForConstructors(String annotationClassName, Class<?> c) { Map<String, Set<String>> classesContainingInjectionPointsForAnnotation; if( hasHadInjectionPoints ) { return delegate.isWorthScanning(c); } else if( c != null ) { classesContainingInjectionPointsForAnnotation = mapAnnotationToMapClassWithInjectionNameToConstructorSet.get(annotationClassName); if( classesContainingInjectionPointsForAnnotation == null ) { return false; } do { if( classesContainingInjectionPointsForAnnotation.containsKey(c.getName()) ) { hasHadInjectionPoints = true; return true; } c = c.getSuperclass(); } while( delegate.isWorthScanning(c) ); } return false; } public Set<Constructor<?>> getAllConstructors(String annotationClassName, Class<?> c) { //System.out.printf("map of methods : %s \n",mapAnnotationToMapClassWithInjectionNameToConstructorSet.toString()); Map<String, Set<String>> classesContainingInjectionPointsForAnnotation = mapAnnotationToMapClassWithInjectionNameToConstructorSet.get(annotationClassName); if( c != null && classesContainingInjectionPointsForAnnotation!= null ) { Set<String> methodNameSet = classesContainingInjectionPointsForAnnotation.get(c.getName()); if( methodNameSet != null ) { Set<Constructor<?>> methodSet = new HashSet<Constructor<?>>(); try { for( String methodNameAndParamClasses : methodNameSet ) { //System.out.printf("Getting method %s of class %s \n",methodNameAndParamClasses,c.getName()); String[] split = methodNameAndParamClasses.split(":"); Class<?>[] paramClass = new Class[split.length-1]; for( int i=1;i<split.length;i++) { paramClass[i-1] = getClass().getClassLoader().loadClass(split[i]); } methodSet.add( c.getDeclaredConstructor( paramClass)); } return methodSet; } catch( Exception ex ) { ex.printStackTrace(); } } } //costly but should not happen return Collections.emptySet(); } }