1 package org.junit.experimental.theories; 2 3 import java.lang.annotation.Annotation; 4 import java.lang.reflect.Constructor; 5 import java.lang.reflect.Method; 6 import java.util.ArrayList; 7 import java.util.Arrays; 8 import java.util.Collections; 9 import java.util.HashMap; 10 import java.util.List; 11 import java.util.Map; 12 13 public class ParameterSignature { 14 15 private static final Map<Class<?>, Class<?>> CONVERTABLE_TYPES_MAP = buildConvertableTypesMap(); 16 buildConvertableTypesMap()17 private static Map<Class<?>, Class<?>> buildConvertableTypesMap() { 18 Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>(); 19 20 putSymmetrically(map, boolean.class, Boolean.class); 21 putSymmetrically(map, byte.class, Byte.class); 22 putSymmetrically(map, short.class, Short.class); 23 putSymmetrically(map, char.class, Character.class); 24 putSymmetrically(map, int.class, Integer.class); 25 putSymmetrically(map, long.class, Long.class); 26 putSymmetrically(map, float.class, Float.class); 27 putSymmetrically(map, double.class, Double.class); 28 29 return Collections.unmodifiableMap(map); 30 } 31 putSymmetrically(Map<T, T> map, T a, T b)32 private static <T> void putSymmetrically(Map<T, T> map, T a, T b) { 33 map.put(a, b); 34 map.put(b, a); 35 } 36 signatures(Method method)37 public static ArrayList<ParameterSignature> signatures(Method method) { 38 return signatures(method.getParameterTypes(), method 39 .getParameterAnnotations()); 40 } 41 signatures(Constructor<?> constructor)42 public static List<ParameterSignature> signatures(Constructor<?> constructor) { 43 return signatures(constructor.getParameterTypes(), constructor 44 .getParameterAnnotations()); 45 } 46 signatures( Class<?>[] parameterTypes, Annotation[][] parameterAnnotations)47 private static ArrayList<ParameterSignature> signatures( 48 Class<?>[] parameterTypes, Annotation[][] parameterAnnotations) { 49 ArrayList<ParameterSignature> sigs = new ArrayList<ParameterSignature>(); 50 for (int i = 0; i < parameterTypes.length; i++) { 51 sigs.add(new ParameterSignature(parameterTypes[i], 52 parameterAnnotations[i])); 53 } 54 return sigs; 55 } 56 57 private final Class<?> type; 58 59 private final Annotation[] annotations; 60 ParameterSignature(Class<?> type, Annotation[] annotations)61 private ParameterSignature(Class<?> type, Annotation[] annotations) { 62 this.type = type; 63 this.annotations = annotations; 64 } 65 canAcceptValue(Object candidate)66 public boolean canAcceptValue(Object candidate) { 67 return (candidate == null) ? !type.isPrimitive() : canAcceptType(candidate.getClass()); 68 } 69 canAcceptType(Class<?> candidate)70 public boolean canAcceptType(Class<?> candidate) { 71 return type.isAssignableFrom(candidate) || 72 isAssignableViaTypeConversion(type, candidate); 73 } 74 canPotentiallyAcceptType(Class<?> candidate)75 public boolean canPotentiallyAcceptType(Class<?> candidate) { 76 return candidate.isAssignableFrom(type) || 77 isAssignableViaTypeConversion(candidate, type) || 78 canAcceptType(candidate); 79 } 80 isAssignableViaTypeConversion(Class<?> targetType, Class<?> candidate)81 private boolean isAssignableViaTypeConversion(Class<?> targetType, Class<?> candidate) { 82 if (CONVERTABLE_TYPES_MAP.containsKey(candidate)) { 83 Class<?> wrapperClass = CONVERTABLE_TYPES_MAP.get(candidate); 84 return targetType.isAssignableFrom(wrapperClass); 85 } else { 86 return false; 87 } 88 } 89 getType()90 public Class<?> getType() { 91 return type; 92 } 93 getAnnotations()94 public List<Annotation> getAnnotations() { 95 return Arrays.asList(annotations); 96 } 97 hasAnnotation(Class<? extends Annotation> type)98 public boolean hasAnnotation(Class<? extends Annotation> type) { 99 return getAnnotation(type) != null; 100 } 101 findDeepAnnotation(Class<T> annotationType)102 public <T extends Annotation> T findDeepAnnotation(Class<T> annotationType) { 103 Annotation[] annotations2 = annotations; 104 return findDeepAnnotation(annotations2, annotationType, 3); 105 } 106 findDeepAnnotation( Annotation[] annotations, Class<T> annotationType, int depth)107 private <T extends Annotation> T findDeepAnnotation( 108 Annotation[] annotations, Class<T> annotationType, int depth) { 109 if (depth == 0) { 110 return null; 111 } 112 for (Annotation each : annotations) { 113 if (annotationType.isInstance(each)) { 114 return annotationType.cast(each); 115 } 116 Annotation candidate = findDeepAnnotation(each.annotationType() 117 .getAnnotations(), annotationType, depth - 1); 118 if (candidate != null) { 119 return annotationType.cast(candidate); 120 } 121 } 122 123 return null; 124 } 125 getAnnotation(Class<T> annotationType)126 public <T extends Annotation> T getAnnotation(Class<T> annotationType) { 127 for (Annotation each : getAnnotations()) { 128 if (annotationType.isInstance(each)) { 129 return annotationType.cast(each); 130 } 131 } 132 return null; 133 } 134 }