1 package com.lexicalscope.fluentreflection;
2
3 import static ch.lambdaj.Lambda.convert;
4 import static com.lexicalscope.fluentreflection.FluentReflection.type;
5 import static java.util.Arrays.asList;
6 import static org.hamcrest.Matchers.*;
7
8 import java.lang.annotation.Annotation;
9 import java.lang.reflect.Constructor;
10 import java.lang.reflect.Field;
11 import java.util.ArrayList;
12 import java.util.List;
13
14 import org.hamcrest.Description;
15 import org.hamcrest.Matcher;
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 public final class ReflectionMatchers {
39 private ReflectionMatchers() { }
40
41
42
43
44
45
46
47
48
49 public static ReflectionMatcher<FluentMember> hasNameStartingWith(final String prefix) {
50 return new MatcherHasNameStartingWith(prefix);
51 }
52
53
54
55
56
57
58
59
60
61 public static ReflectionMatcher<FluentMember> hasNameEndingWith(final String suffix) {
62 return new MatcherHasNameEndingWith(suffix);
63 }
64
65
66
67
68
69
70
71
72
73
74 public static ReflectionMatcher<FluentMember> hasNameMatching(final String regex) {
75 return new MatcherHasNameMatching(regex);
76 }
77
78
79
80
81
82
83
84
85
86
87 public static ReflectionMatcher<FluentMember> hasNameContaining(final CharSequence substring) {
88 return new MatcherHasNameContaining(substring);
89 }
90
91
92
93
94
95
96
97
98
99 public static ReflectionMatcher<FluentMember> hasName(final String name) {
100 return new MatcherNamed(name);
101 }
102
103 public static ReflectionMatcher<FluentMember> hasPropertyName(final String name) {
104 return new MatcherPropertyName(name);
105 }
106
107
108
109
110
111
112
113
114
115 public static ReflectionMatcher<FluentMember> declaredBy(final Class<?> declaringClass) {
116 return new MatcherDeclaredBy(reflectingOn(declaringClass));
117 }
118
119 public static ReflectionMatcher<FluentClass<?>> hasNoInterfaces() {
120 return new MatcherHasNoInterfaces();
121 }
122
123 public static ReflectionMatcher<FluentClass<?>> hasNoSuperclasses() {
124 return new MatcherHasNoSuperclasses();
125 }
126
127 public static ReflectionMatcher<FluentClass<?>> hasInterface(final Class<?> interfac3) {
128 return new MatcherHasInterface(interfac3);
129 }
130
131 public static ReflectionMatcher<FluentClass<?>> isAnInterface() {
132 return new MatcherIsInterface();
133 }
134
135 public static ReflectionMatcher<FluentClass<?>> hasSimpleName(final String simpleName) {
136 return new MatcherHasSimpleName(equalTo(simpleName));
137 }
138
139 public static ReflectionMatcher<FluentClass<?>> anyReflectedType() {
140 return new MatcherAnyReflectedType();
141 }
142
143 public static ReflectionMatcher<FluentClass<?>> reflectingOn(final Class<?> klass) {
144 return new MatcherReflectingOn(klass);
145 }
146
147 public static ReflectionMatcher<FluentClass<?>> assignableFrom(final Class<?> klass) {
148 return new MatcherAssignableFrom(klass);
149 }
150
151 public static ReflectionMatcher<FluentClass<?>> assignableFrom(final FluentClass<?> klass) {
152 return new MatcherAssignableFrom(klass);
153 }
154
155 public static ReflectionMatcher<FluentConstructor<?>> reflectingOnConstructor(
156 final Constructor<?> constructor) {
157 return new MatcherConstructorReflectingOn(constructor);
158 }
159
160 public static ReflectionMatcher<FluentMember> hasArgumentCount(final int argumentCount) {
161 return new MatcherArgumentCount(argumentCount);
162 }
163
164 public static ReflectionMatcher<FluentMember> hasNoArguments() {
165 return hasArguments();
166 }
167
168 public static ReflectionMatcher<FluentMember> hasArguments(final Class<?>... argTypes) {
169 return hasArgumentList(asList(argTypes));
170 }
171
172 public static ReflectionMatcher<FluentMember> canBeCalledWithArguments(final Object ... args) {
173 final List<Matcher<? super FluentClass<?>>> types = new ArrayList<Matcher<? super FluentClass<?>>>();
174 for (final Object object : args) {
175 if(object == null) {
176 types.add(anyReflectedType());
177 } else {
178 final FluentClass<? extends Object> argumentType = type(object.getClass());
179 if(argumentType.isPrimitive()) {
180 types.add(assignableFrom(argumentType).or(assignableFrom(argumentType.boxedType())));
181 } else if(argumentType.isUnboxable()) {
182 types.add(assignableFrom(argumentType).or(assignableFrom(argumentType.unboxedType())));
183 } else {
184 types.add(assignableFrom(argumentType));
185 }
186 }
187 }
188 return hasArgumentListMatching(types);
189 }
190
191 public static ReflectionMatcher<FluentMember> hasArgumentList(final List<Class<?>> argTypes) {
192 return new MatcherArgumentTypes(convert(argTypes, new ConvertClassToReflectedTypeAssignableMatcher()));
193 }
194
195 public static ReflectionMatcher<FluentMember> hasArgumentsMatching(
196 final Matcher<? super FluentClass<?>>... argTypes) {
197 return hasArgumentListMatching(asList(argTypes));
198 }
199
200 public static ReflectionMatcher<FluentMember> hasArgumentListMatching(
201 final List<Matcher<? super FluentClass<?>>> argTypes) {
202 return new MatcherArgumentTypes(argTypes);
203 }
204
205 public static ReflectionMatcher<FluentMember> hasReflectedArguments(
206 final FluentClass<?>... argTypes) {
207 return hasReflectedArgumentList(asList(argTypes));
208 }
209
210 public static ReflectionMatcher<FluentMember> hasReflectedArgumentList(
211 final List<FluentClass<?>> argTypes) {
212 return new MatcherArgumentTypes(convert(argTypes, new ConvertReflectedTypeToReflectedTypeAssignableMatcher()));
213 }
214
215 public static ReflectionMatcher<FluentMember> hasType(final Class<?> returnType) {
216 if (returnType == null) {
217 return hasVoidType();
218 }
219 return new MatcherReturnType(new ConvertClassToReflectedTypeAssignableMatcher().convert(returnType));
220 }
221
222 public static ReflectionMatcher<FluentMember> hasVoidType() {
223 return new MatcherReturnType(reflectingOn(void.class));
224 }
225
226 public static ReflectionMatcher<FluentMember> hasNonVoidType() {
227 return not(hasVoidType());
228 }
229
230 public static ReflectionMatcher<FluentMember> hasType(final FluentClass<?> returnType) {
231 if (returnType == null) {
232 return hasVoidType();
233 }
234 return new MatcherReturnType(new ConvertReflectedTypeToReflectedTypeAssignableMatcher().convert(returnType));
235 }
236
237 public static ReflectionMatcher<FluentMember> hasType(final Matcher<? super FluentClass<?>> returnType) {
238 return new MatcherReturnType(returnType);
239 }
240
241 public static ReflectionMatcher<FluentAnnotated> annotatedWith(final Class<? extends Annotation> annotation) {
242 return new MatcherCallableAnnotatedWith(annotation);
243 }
244
245 public static ReflectionMatcher<FluentMember> isStatic() {
246 return new MatcherIsStatic();
247 }
248
249 public static ReflectionMatcher<FluentMember> isNotStatic() {
250 return not(isStatic());
251 }
252
253 public static <T> ReflectionMatcher<T> not(final ReflectionMatcher<T> matcher) {
254 return new ReflectionMatcher<T>() {
255 @Override protected boolean matchesSafely(final T item) {
256 return !matcher.matches(item);
257 }
258
259 @Override public void describeTo(final Description description) {
260 description.appendText("not ").appendDescriptionOf(matcher);
261 }
262 };
263 }
264
265 public static ReflectionMatcher<FluentMember> isQuery() {
266 return hasNoArguments().and(not(hasVoidType()));
267 }
268
269 public static ReflectionMatcher<FluentMember> isGetter() {
270 return hasNameStartingWith("get").and(isQuery());
271 }
272
273 public static ReflectionMatcher<FluentMember> isMutator() {
274 return hasArgumentsMatching(anything()).and(
275 not(hasNonVoidType()));
276 }
277
278 public static ReflectionMatcher<FluentMember> isSetter() {
279 return hasNameStartingWith("set").and(isMutator());
280 }
281
282 public static ReflectionMatcher<FluentMember> isExistence() {
283 return isQuery().
284 and(hasType(boolean.class).or(hasType(Boolean.class))).
285 and(hasNameStartingWith("is").or(hasNameStartingWith("has")));
286 }
287
288 public static ReflectionMatcher<FluentMember> isHashCodeMethod() {
289 return hasNoArguments().
290 and(hasType(int.class)).
291 and(hasName("hashCode"));
292 }
293
294 public static ReflectionMatcher<FluentMember> isEqualsMethod() {
295 return hasArguments(Object.class).
296 and(hasType(boolean.class)).
297 and(hasName("equals"));
298 }
299
300 public static ReflectionMatcher<FluentMember> isToStringMethod() {
301 return hasNoArguments().
302 and(hasType(String.class)).
303 and(hasName("toString"));
304 }
305
306 public static ReflectionMatcher<FluentMember> isPublicMethod() {
307 return new MatcherPublic();
308 }
309
310 public static Matcher<? super FluentMember> isDeclaredByStrictSubtypeOf(final Class<?> klass) {
311 return new MatcherDeclaredBy(isStrictSubtypeOf(klass));
312 }
313
314 public static Matcher<? super FluentClass<?>> isStrictSubtypeOf(final Class<?> klass) {
315 return new MatcherStrictSubtypeOf(klass);
316 }
317
318 public static ReflectionMatcher<FluentField> isReflectingOnField(final Field field) {
319 return new MatcherFieldReflectingOn(field);
320 }
321
322 public static ReflectionMatcher<FluentMember> isFinal() {
323 return new MatcherFinalMember();
324 }
325
326 public static ReflectionMatcher<FluentMember> hasVisibility(final Visibility visibility) {
327 return new MatcherVisibility(visibility);
328 }
329 }