• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.inject.matcher;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 
22 import java.io.Serializable;
23 import java.lang.annotation.Annotation;
24 import java.lang.annotation.Retention;
25 import java.lang.annotation.RetentionPolicy;
26 import java.lang.reflect.AnnotatedElement;
27 import java.lang.reflect.Method;
28 
29 /**
30  * Matcher implementations. Supports matching classes and methods.
31  *
32  * @author crazybob@google.com (Bob Lee)
33  */
34 public class Matchers {
Matchers()35   private Matchers() {}
36 
37   /** Returns a matcher which matches any input. */
any()38   public static Matcher<Object> any() {
39     return ANY;
40   }
41 
42   private static final Matcher<Object> ANY = new Any();
43 
44   private static class Any extends AbstractMatcher<Object> implements Serializable {
45     @Override
matches(Object o)46     public boolean matches(Object o) {
47       return true;
48     }
49 
50     @Override
toString()51     public String toString() {
52       return "any()";
53     }
54 
readResolve()55     public Object readResolve() {
56       return any();
57     }
58 
59     private static final long serialVersionUID = 0;
60   }
61 
62   /** Inverts the given matcher. */
not(final Matcher<? super T> p)63   public static <T> Matcher<T> not(final Matcher<? super T> p) {
64     return new Not<T>(p);
65   }
66 
67   private static class Not<T> extends AbstractMatcher<T> implements Serializable {
68     final Matcher<? super T> delegate;
69 
Not(Matcher<? super T> delegate)70     private Not(Matcher<? super T> delegate) {
71       this.delegate = checkNotNull(delegate, "delegate");
72     }
73 
74     @Override
matches(T t)75     public boolean matches(T t) {
76       return !delegate.matches(t);
77     }
78 
79     @Override
equals(Object other)80     public boolean equals(Object other) {
81       return other instanceof Not && ((Not) other).delegate.equals(delegate);
82     }
83 
84     @Override
hashCode()85     public int hashCode() {
86       return -delegate.hashCode();
87     }
88 
89     @Override
toString()90     public String toString() {
91       return "not(" + delegate + ")";
92     }
93 
94     private static final long serialVersionUID = 0;
95   }
96 
checkForRuntimeRetention(Class<? extends Annotation> annotationType)97   private static void checkForRuntimeRetention(Class<? extends Annotation> annotationType) {
98     Retention retention = annotationType.getAnnotation(Retention.class);
99     checkArgument(
100         retention != null && retention.value() == RetentionPolicy.RUNTIME,
101         "Annotation %s is missing RUNTIME retention",
102         annotationType.getSimpleName());
103   }
104 
105   /** Returns a matcher which matches elements (methods, classes, etc.) with a given annotation. */
annotatedWith( final Class<? extends Annotation> annotationType)106   public static Matcher<AnnotatedElement> annotatedWith(
107       final Class<? extends Annotation> annotationType) {
108     return new AnnotatedWithType(annotationType);
109   }
110 
111   private static class AnnotatedWithType extends AbstractMatcher<AnnotatedElement>
112       implements Serializable {
113     private final Class<? extends Annotation> annotationType;
114 
AnnotatedWithType(Class<? extends Annotation> annotationType)115     public AnnotatedWithType(Class<? extends Annotation> annotationType) {
116       this.annotationType = checkNotNull(annotationType, "annotation type");
117       checkForRuntimeRetention(annotationType);
118     }
119 
120     @Override
matches(AnnotatedElement element)121     public boolean matches(AnnotatedElement element) {
122       return element.isAnnotationPresent(annotationType);
123     }
124 
125     @Override
equals(Object other)126     public boolean equals(Object other) {
127       return other instanceof AnnotatedWithType
128           && ((AnnotatedWithType) other).annotationType.equals(annotationType);
129     }
130 
131     @Override
hashCode()132     public int hashCode() {
133       return 37 * annotationType.hashCode();
134     }
135 
136     @Override
toString()137     public String toString() {
138       return "annotatedWith(" + annotationType.getSimpleName() + ".class)";
139     }
140 
141     private static final long serialVersionUID = 0;
142   }
143 
144   /** Returns a matcher which matches elements (methods, classes, etc.) with a given annotation. */
annotatedWith(final Annotation annotation)145   public static Matcher<AnnotatedElement> annotatedWith(final Annotation annotation) {
146     return new AnnotatedWith(annotation);
147   }
148 
149   private static class AnnotatedWith extends AbstractMatcher<AnnotatedElement>
150       implements Serializable {
151     private final Annotation annotation;
152 
AnnotatedWith(Annotation annotation)153     public AnnotatedWith(Annotation annotation) {
154       this.annotation = checkNotNull(annotation, "annotation");
155       checkForRuntimeRetention(annotation.annotationType());
156     }
157 
158     @Override
matches(AnnotatedElement element)159     public boolean matches(AnnotatedElement element) {
160       Annotation fromElement = element.getAnnotation(annotation.annotationType());
161       return fromElement != null && annotation.equals(fromElement);
162     }
163 
164     @Override
equals(Object other)165     public boolean equals(Object other) {
166       return other instanceof AnnotatedWith
167           && ((AnnotatedWith) other).annotation.equals(annotation);
168     }
169 
170     @Override
hashCode()171     public int hashCode() {
172       return 37 * annotation.hashCode();
173     }
174 
175     @Override
toString()176     public String toString() {
177       return "annotatedWith(" + annotation + ")";
178     }
179 
180     private static final long serialVersionUID = 0;
181   }
182 
183   /** Returns a matcher which matches subclasses of the given type (as well as the given type). */
subclassesOf(final Class<?> superclass)184   public static Matcher<Class> subclassesOf(final Class<?> superclass) {
185     return new SubclassesOf(superclass);
186   }
187 
188   private static class SubclassesOf extends AbstractMatcher<Class> implements Serializable {
189     private final Class<?> superclass;
190 
SubclassesOf(Class<?> superclass)191     public SubclassesOf(Class<?> superclass) {
192       this.superclass = checkNotNull(superclass, "superclass");
193     }
194 
195     @Override
matches(Class subclass)196     public boolean matches(Class subclass) {
197       return superclass.isAssignableFrom(subclass);
198     }
199 
200     @Override
equals(Object other)201     public boolean equals(Object other) {
202       return other instanceof SubclassesOf && ((SubclassesOf) other).superclass.equals(superclass);
203     }
204 
205     @Override
hashCode()206     public int hashCode() {
207       return 37 * superclass.hashCode();
208     }
209 
210     @Override
toString()211     public String toString() {
212       return "subclassesOf(" + superclass.getSimpleName() + ".class)";
213     }
214 
215     private static final long serialVersionUID = 0;
216   }
217 
218   /** Returns a matcher which matches objects equal to the given object. */
only(Object value)219   public static Matcher<Object> only(Object value) {
220     return new Only(value);
221   }
222 
223   private static class Only extends AbstractMatcher<Object> implements Serializable {
224     private final Object value;
225 
Only(Object value)226     public Only(Object value) {
227       this.value = checkNotNull(value, "value");
228     }
229 
230     @Override
matches(Object other)231     public boolean matches(Object other) {
232       return value.equals(other);
233     }
234 
235     @Override
equals(Object other)236     public boolean equals(Object other) {
237       return other instanceof Only && ((Only) other).value.equals(value);
238     }
239 
240     @Override
hashCode()241     public int hashCode() {
242       return 37 * value.hashCode();
243     }
244 
245     @Override
toString()246     public String toString() {
247       return "only(" + value + ")";
248     }
249 
250     private static final long serialVersionUID = 0;
251   }
252 
253   /** Returns a matcher which matches only the given object. */
identicalTo(final Object value)254   public static Matcher<Object> identicalTo(final Object value) {
255     return new IdenticalTo(value);
256   }
257 
258   private static class IdenticalTo extends AbstractMatcher<Object> implements Serializable {
259     private final Object value;
260 
IdenticalTo(Object value)261     public IdenticalTo(Object value) {
262       this.value = checkNotNull(value, "value");
263     }
264 
265     @Override
matches(Object other)266     public boolean matches(Object other) {
267       return value == other;
268     }
269 
270     @Override
equals(Object other)271     public boolean equals(Object other) {
272       return other instanceof IdenticalTo && ((IdenticalTo) other).value == value;
273     }
274 
275     @Override
hashCode()276     public int hashCode() {
277       return 37 * System.identityHashCode(value);
278     }
279 
280     @Override
toString()281     public String toString() {
282       return "identicalTo(" + value + ")";
283     }
284 
285     private static final long serialVersionUID = 0;
286   }
287 
288   /**
289    * Returns a matcher which matches classes in the given package. Packages are specific to their
290    * classloader, so classes with the same package name may not have the same package at runtime.
291    */
inPackage(final Package targetPackage)292   public static Matcher<Class> inPackage(final Package targetPackage) {
293     return new InPackage(targetPackage);
294   }
295 
296   private static class InPackage extends AbstractMatcher<Class> implements Serializable {
297     private final transient Package targetPackage;
298     private final String packageName;
299 
InPackage(Package targetPackage)300     public InPackage(Package targetPackage) {
301       this.targetPackage = checkNotNull(targetPackage, "package");
302       this.packageName = targetPackage.getName();
303     }
304 
305     @Override
matches(Class c)306     public boolean matches(Class c) {
307       return c.getPackage().equals(targetPackage);
308     }
309 
310     @Override
equals(Object other)311     public boolean equals(Object other) {
312       return other instanceof InPackage && ((InPackage) other).targetPackage.equals(targetPackage);
313     }
314 
315     @Override
hashCode()316     public int hashCode() {
317       return 37 * targetPackage.hashCode();
318     }
319 
320     @Override
toString()321     public String toString() {
322       return "inPackage(" + targetPackage.getName() + ")";
323     }
324 
readResolve()325     public Object readResolve() {
326       return inPackage(Package.getPackage(packageName));
327     }
328 
329     private static final long serialVersionUID = 0;
330   }
331 
332   /**
333    * Returns a matcher which matches classes in the given package and its subpackages. Unlike {@link
334    * #inPackage(Package) inPackage()}, this matches classes from any classloader.
335    *
336    * @since 2.0
337    */
inSubpackage(final String targetPackageName)338   public static Matcher<Class> inSubpackage(final String targetPackageName) {
339     return new InSubpackage(targetPackageName);
340   }
341 
342   private static class InSubpackage extends AbstractMatcher<Class> implements Serializable {
343     private final String targetPackageName;
344 
InSubpackage(String targetPackageName)345     public InSubpackage(String targetPackageName) {
346       this.targetPackageName = targetPackageName;
347     }
348 
349     @Override
matches(Class c)350     public boolean matches(Class c) {
351       String classPackageName = c.getPackage().getName();
352       return classPackageName.equals(targetPackageName)
353           || classPackageName.startsWith(targetPackageName + ".");
354     }
355 
356     @Override
equals(Object other)357     public boolean equals(Object other) {
358       return other instanceof InSubpackage
359           && ((InSubpackage) other).targetPackageName.equals(targetPackageName);
360     }
361 
362     @Override
hashCode()363     public int hashCode() {
364       return 37 * targetPackageName.hashCode();
365     }
366 
367     @Override
toString()368     public String toString() {
369       return "inSubpackage(" + targetPackageName + ")";
370     }
371 
372     private static final long serialVersionUID = 0;
373   }
374 
375   /** Returns a matcher which matches methods with matching return types. */
returns(final Matcher<? super Class<?>> returnType)376   public static Matcher<Method> returns(final Matcher<? super Class<?>> returnType) {
377     return new Returns(returnType);
378   }
379 
380   private static class Returns extends AbstractMatcher<Method> implements Serializable {
381     private final Matcher<? super Class<?>> returnType;
382 
Returns(Matcher<? super Class<?>> returnType)383     public Returns(Matcher<? super Class<?>> returnType) {
384       this.returnType = checkNotNull(returnType, "return type matcher");
385     }
386 
387     @Override
matches(Method m)388     public boolean matches(Method m) {
389       return returnType.matches(m.getReturnType());
390     }
391 
392     @Override
equals(Object other)393     public boolean equals(Object other) {
394       return other instanceof Returns && ((Returns) other).returnType.equals(returnType);
395     }
396 
397     @Override
hashCode()398     public int hashCode() {
399       return 37 * returnType.hashCode();
400     }
401 
402     @Override
toString()403     public String toString() {
404       return "returns(" + returnType + ")";
405     }
406 
407     private static final long serialVersionUID = 0;
408   }
409 }
410