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.List;
009
010public class ParameterSignature {
011    public static ArrayList<ParameterSignature> signatures(Method method) {
012        return signatures(method.getParameterTypes(), method
013                .getParameterAnnotations());
014    }
015
016    public static List<ParameterSignature> signatures(Constructor<?> constructor) {
017        return signatures(constructor.getParameterTypes(), constructor
018                .getParameterAnnotations());
019    }
020
021    private static ArrayList<ParameterSignature> signatures(
022            Class<?>[] parameterTypes, Annotation[][] parameterAnnotations) {
023        ArrayList<ParameterSignature> sigs = new ArrayList<ParameterSignature>();
024        for (int i = 0; i < parameterTypes.length; i++) {
025            sigs.add(new ParameterSignature(parameterTypes[i],
026                    parameterAnnotations[i]));
027        }
028        return sigs;
029    }
030
031    private final Class<?> type;
032
033    private final Annotation[] annotations;
034
035    private ParameterSignature(Class<?> type, Annotation[] annotations) {
036        this.type = type;
037        this.annotations = annotations;
038    }
039
040    public boolean canAcceptValue(Object candidate) {
041        return (candidate == null) ? !type.isPrimitive() : canAcceptType(candidate.getClass());
042    }
043
044    public boolean canAcceptType(Class<?> candidate) {
045        return type.isAssignableFrom(candidate);
046    }
047
048    public Class<?> getType() {
049        return type;
050    }
051
052    public List<Annotation> getAnnotations() {
053        return Arrays.asList(annotations);
054    }
055
056    public boolean canAcceptArrayType(Class<?> type) {
057        return type.isArray() && canAcceptType(type.getComponentType());
058    }
059
060    public boolean hasAnnotation(Class<? extends Annotation> type) {
061        return getAnnotation(type) != null;
062    }
063
064    public <T extends Annotation> T findDeepAnnotation(Class<T> annotationType) {
065        Annotation[] annotations2 = annotations;
066        return findDeepAnnotation(annotations2, annotationType, 3);
067    }
068
069    private <T extends Annotation> T findDeepAnnotation(
070            Annotation[] annotations, Class<T> annotationType, int depth) {
071        if (depth == 0) {
072            return null;
073        }
074        for (Annotation each : annotations) {
075            if (annotationType.isInstance(each)) {
076                return annotationType.cast(each);
077            }
078            Annotation candidate = findDeepAnnotation(each.annotationType()
079                    .getAnnotations(), annotationType, depth - 1);
080            if (candidate != null) {
081                return annotationType.cast(candidate);
082            }
083        }
084
085        return null;
086    }
087
088    public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
089        for (Annotation each : getAnnotations()) {
090            if (annotationType.isInstance(each)) {
091                return annotationType.cast(each);
092            }
093        }
094        return null;
095    }
096}