View Javadoc

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   * Copyright 2011 Tim Wood
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   * http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   */
32  
33  /**
34   * A whole bunch of matchers suitable for selecting program elements
35   *
36   * @author tim
37   */
38  public final class ReflectionMatchers {
39      private ReflectionMatchers() { }
40  
41      /**
42       * Matches a prefix of the name of a callable
43       *
44       * @param prefix
45       *            the prefix
46       *
47       * @return true iff the argument is a prefix of the name of the callable
48       */
49      public static ReflectionMatcher<FluentMember> hasNameStartingWith(final String prefix) {
50          return new MatcherHasNameStartingWith(prefix);
51      }
52  
53      /**
54       * Matches a suffix of the name of a callable
55       *
56       * @param suffix
57       *            the suffix
58       *
59       * @return true iff the argument is a suffix of the name of the callable
60       */
61      public static ReflectionMatcher<FluentMember> hasNameEndingWith(final String suffix) {
62          return new MatcherHasNameEndingWith(suffix);
63      }
64  
65      /**
66       * Matches a regular expression against the name of a callable
67       *
68       * @param regex
69       *            the regular expression
70       *
71       * @return true iff the argument is a regular expression matching the name
72       *         of the callable
73       */
74      public static ReflectionMatcher<FluentMember> hasNameMatching(final String regex) {
75          return new MatcherHasNameMatching(regex);
76      }
77  
78      /**
79       * Matches a substring of the name of a callable
80       *
81       * @param substring
82       *            the substring
83       *
84       * @return true iff the argument is contained within the name of the
85       *         callable
86       */
87      public static ReflectionMatcher<FluentMember> hasNameContaining(final CharSequence substring) {
88          return new MatcherHasNameContaining(substring);
89      }
90  
91      /**
92       * Matches the name of a callable
93       *
94       * @param name
95       *            the name
96       *
97       * @return true iff the argument is equal to the name of the callable
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      * Matches the declaring class of a callable
109      *
110      * @param declaringClass
111      *            the declaring class
112      *
113      * @return true iff the callable is declared by the argument
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 }