1b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot/**
2b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot *
3b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */
4b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpackage org.junit.experimental.theories;
5b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
6b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.annotation.Annotation;
7b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Constructor;
8b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Method;
9b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.ArrayList;
10b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.Arrays;
11b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.List;
12b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
13b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpublic class ParameterSignature {
14b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public static ArrayList<ParameterSignature> signatures(Method method) {
15b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return signatures(method.getParameterTypes(), method
16b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				.getParameterAnnotations());
17b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
18b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
19b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public static List<ParameterSignature> signatures(Constructor<?> constructor) {
20b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return signatures(constructor.getParameterTypes(), constructor
21b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				.getParameterAnnotations());
22b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
23b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
24b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private static ArrayList<ParameterSignature> signatures(
25b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			Class<?>[] parameterTypes, Annotation[][] parameterAnnotations) {
26b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		ArrayList<ParameterSignature> sigs= new ArrayList<ParameterSignature>();
27b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		for (int i= 0; i < parameterTypes.length; i++) {
28b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			sigs.add(new ParameterSignature(parameterTypes[i],
29b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot					parameterAnnotations[i]));
30b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		}
31b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return sigs;
32b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
33b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
34b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private final Class<?> type;
35b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
36b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private final Annotation[] annotations;
37b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
38b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private ParameterSignature(Class<?> type, Annotation[] annotations) {
39b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		this.type= type;
40b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		this.annotations= annotations;
41b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
42b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
43b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public boolean canAcceptType(Class<?> candidate) {
44b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return type.isAssignableFrom(candidate);
45b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
46b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
47b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public Class<?> getType() {
48b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return type;
49b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
50b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
51b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public List<Annotation> getAnnotations() {
52b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return Arrays.asList(annotations);
53b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
54b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
55b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public boolean canAcceptArrayType(Class<?> type) {
56b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return type.isArray() && canAcceptType(type.getComponentType());
57b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
58b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
59b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public boolean hasAnnotation(Class<? extends Annotation> type) {
60b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return getAnnotation(type) != null;
61b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
62b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
63b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public <T extends Annotation> T findDeepAnnotation(Class<T> annotationType) {
64b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		Annotation[] annotations2= annotations;
65b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return findDeepAnnotation(annotations2, annotationType, 3);
66b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
67b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
68b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private <T extends Annotation> T findDeepAnnotation(
69b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			Annotation[] annotations, Class<T> annotationType, int depth) {
70b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		if (depth == 0)
71b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			return null;
72b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		for (Annotation each : annotations) {
73b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			if (annotationType.isInstance(each))
74b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				return annotationType.cast(each);
75b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			Annotation candidate= findDeepAnnotation(each.annotationType()
76b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot					.getAnnotations(), annotationType, depth - 1);
77b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			if (candidate != null)
78b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				return annotationType.cast(candidate);
79b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		}
80b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
81b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return null;
82b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
83b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
84b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
85b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		for (Annotation each : getAnnotations())
86b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			if (annotationType.isInstance(each))
87b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				return annotationType.cast(each);
88b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return null;
89b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
90b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot}