001package org.junit.experimental.theories; 002 003import java.lang.annotation.Annotation; 004import java.lang.reflect.Constructor; 005import java.lang.reflect.Method; 006import java.util.ArrayList; 007import java.util.Arrays; 008import java.util.Collections; 009import java.util.HashMap; 010import java.util.List; 011import java.util.Map; 012 013public class ParameterSignature { 014 015 private static final Map<Class<?>, Class<?>> CONVERTABLE_TYPES_MAP = buildConvertableTypesMap(); 016 017 private static Map<Class<?>, Class<?>> buildConvertableTypesMap() { 018 Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>(); 019 020 putSymmetrically(map, boolean.class, Boolean.class); 021 putSymmetrically(map, byte.class, Byte.class); 022 putSymmetrically(map, short.class, Short.class); 023 putSymmetrically(map, char.class, Character.class); 024 putSymmetrically(map, int.class, Integer.class); 025 putSymmetrically(map, long.class, Long.class); 026 putSymmetrically(map, float.class, Float.class); 027 putSymmetrically(map, double.class, Double.class); 028 029 return Collections.unmodifiableMap(map); 030 } 031 032 private static <T> void putSymmetrically(Map<T, T> map, T a, T b) { 033 map.put(a, b); 034 map.put(b, a); 035 } 036 037 public static ArrayList<ParameterSignature> signatures(Method method) { 038 return signatures(method.getParameterTypes(), method 039 .getParameterAnnotations()); 040 } 041 042 public static List<ParameterSignature> signatures(Constructor<?> constructor) { 043 return signatures(constructor.getParameterTypes(), constructor 044 .getParameterAnnotations()); 045 } 046 047 private static ArrayList<ParameterSignature> signatures( 048 Class<?>[] parameterTypes, Annotation[][] parameterAnnotations) { 049 ArrayList<ParameterSignature> sigs = new ArrayList<ParameterSignature>(); 050 for (int i = 0; i < parameterTypes.length; i++) { 051 sigs.add(new ParameterSignature(parameterTypes[i], 052 parameterAnnotations[i])); 053 } 054 return sigs; 055 } 056 057 private final Class<?> type; 058 059 private final Annotation[] annotations; 060 061 private ParameterSignature(Class<?> type, Annotation[] annotations) { 062 this.type = type; 063 this.annotations = annotations; 064 } 065 066 public boolean canAcceptValue(Object candidate) { 067 return (candidate == null) ? !type.isPrimitive() : canAcceptType(candidate.getClass()); 068 } 069 070 public boolean canAcceptType(Class<?> candidate) { 071 return type.isAssignableFrom(candidate) || 072 isAssignableViaTypeConversion(type, candidate); 073 } 074 075 public boolean canPotentiallyAcceptType(Class<?> candidate) { 076 return candidate.isAssignableFrom(type) || 077 isAssignableViaTypeConversion(candidate, type) || 078 canAcceptType(candidate); 079 } 080 081 private boolean isAssignableViaTypeConversion(Class<?> targetType, Class<?> candidate) { 082 if (CONVERTABLE_TYPES_MAP.containsKey(candidate)) { 083 Class<?> wrapperClass = CONVERTABLE_TYPES_MAP.get(candidate); 084 return targetType.isAssignableFrom(wrapperClass); 085 } else { 086 return false; 087 } 088 } 089 090 public Class<?> getType() { 091 return type; 092 } 093 094 public List<Annotation> getAnnotations() { 095 return Arrays.asList(annotations); 096 } 097 098 public boolean hasAnnotation(Class<? extends Annotation> type) { 099 return getAnnotation(type) != null; 100 } 101 102 public <T extends Annotation> T findDeepAnnotation(Class<T> annotationType) { 103 Annotation[] annotations2 = annotations; 104 return findDeepAnnotation(annotations2, annotationType, 3); 105 } 106 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 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}