• 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   /**
38    * Returns a matcher which matches any input.
39    */
any()40   public static Matcher<Object> any() {
41     return ANY;
42   }
43 
44   private static final Matcher<Object> ANY = new Any();
45 
46   private static class Any extends AbstractMatcher<Object> implements Serializable {
matches(Object o)47     public boolean matches(Object o) {
48       return true;
49     }
50 
toString()51     @Override 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   /**
63    * Inverts the given matcher.
64    */
not(final Matcher<? super T> p)65   public static <T> Matcher<T> not(final Matcher<? super T> p) {
66     return new Not<T>(p);
67   }
68 
69   private static class Not<T> extends AbstractMatcher<T> implements Serializable {
70     final Matcher<? super T> delegate;
71 
Not(Matcher<? super T> delegate)72     private Not(Matcher<? super T> delegate) {
73       this.delegate = checkNotNull(delegate, "delegate");
74     }
75 
matches(T t)76     public boolean matches(T t) {
77       return !delegate.matches(t);
78     }
79 
equals(Object other)80     @Override public boolean equals(Object other) {
81       return other instanceof Not
82           && ((Not) other).delegate.equals(delegate);
83     }
84 
hashCode()85     @Override public int hashCode() {
86       return -delegate.hashCode();
87     }
88 
toString()89     @Override public String toString() {
90       return "not(" + delegate + ")";
91     }
92 
93     private static final long serialVersionUID = 0;
94   }
95 
checkForRuntimeRetention( Class<? extends Annotation> annotationType)96   private static void checkForRuntimeRetention(
97       Class<? extends Annotation> annotationType) {
98     Retention retention = annotationType.getAnnotation(Retention.class);
99     checkArgument(retention != null && retention.value() == RetentionPolicy.RUNTIME,
100         "Annotation %s is missing RUNTIME retention", annotationType.getSimpleName());
101   }
102 
103   /**
104    * Returns a matcher which matches elements (methods, classes, etc.)
105    * with a given annotation.
106    */
annotatedWith( final Class<? extends Annotation> annotationType)107   public static Matcher<AnnotatedElement> annotatedWith(
108       final Class<? extends Annotation> annotationType) {
109     return new AnnotatedWithType(annotationType);
110   }
111 
112   private static class AnnotatedWithType extends AbstractMatcher<AnnotatedElement>
113       implements Serializable {
114     private final Class<? extends Annotation> annotationType;
115 
AnnotatedWithType(Class<? extends Annotation> annotationType)116     public AnnotatedWithType(Class<? extends Annotation> annotationType) {
117       this.annotationType = checkNotNull(annotationType, "annotation type");
118       checkForRuntimeRetention(annotationType);
119     }
120 
matches(AnnotatedElement element)121     public boolean matches(AnnotatedElement element) {
122       return element.isAnnotationPresent(annotationType);
123     }
124 
equals(Object other)125     @Override public boolean equals(Object other) {
126       return other instanceof AnnotatedWithType
127           && ((AnnotatedWithType) other).annotationType.equals(annotationType);
128     }
129 
hashCode()130     @Override public int hashCode() {
131       return 37 * annotationType.hashCode();
132     }
133 
toString()134     @Override public String toString() {
135       return "annotatedWith(" + annotationType.getSimpleName() + ".class)";
136     }
137 
138     private static final long serialVersionUID = 0;
139   }
140 
141   /**
142    * Returns a matcher which matches elements (methods, classes, etc.)
143    * with a given annotation.
144    */
annotatedWith( final Annotation annotation)145   public static Matcher<AnnotatedElement> annotatedWith(
146       final Annotation annotation) {
147     return new AnnotatedWith(annotation);
148   }
149 
150   private static class AnnotatedWith extends AbstractMatcher<AnnotatedElement>
151       implements Serializable {
152     private final Annotation annotation;
153 
AnnotatedWith(Annotation annotation)154     public AnnotatedWith(Annotation annotation) {
155       this.annotation = checkNotNull(annotation, "annotation");
156       checkForRuntimeRetention(annotation.annotationType());
157     }
158 
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 
equals(Object other)164     @Override public boolean equals(Object other) {
165       return other instanceof AnnotatedWith
166           && ((AnnotatedWith) other).annotation.equals(annotation);
167     }
168 
hashCode()169     @Override public int hashCode() {
170       return 37 * annotation.hashCode();
171     }
172 
toString()173     @Override public String toString() {
174       return "annotatedWith(" + annotation + ")";
175     }
176 
177     private static final long serialVersionUID = 0;
178   }
179 
180   /**
181    * Returns a matcher which matches subclasses of the given type (as well as
182    * the given type).
183    */
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>
189       implements Serializable {
190     private final Class<?> superclass;
191 
SubclassesOf(Class<?> superclass)192     public SubclassesOf(Class<?> superclass) {
193       this.superclass = checkNotNull(superclass, "superclass");
194     }
195 
matches(Class subclass)196     public boolean matches(Class subclass) {
197       return superclass.isAssignableFrom(subclass);
198     }
199 
equals(Object other)200     @Override public boolean equals(Object other) {
201       return other instanceof SubclassesOf
202           && ((SubclassesOf) other).superclass.equals(superclass);
203     }
204 
hashCode()205     @Override public int hashCode() {
206       return 37 * superclass.hashCode();
207     }
208 
toString()209     @Override public String toString() {
210       return "subclassesOf(" + superclass.getSimpleName() + ".class)";
211     }
212 
213     private static final long serialVersionUID = 0;
214   }
215 
216   /**
217    * Returns a matcher which matches objects equal to the given object.
218    */
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>
224       implements Serializable {
225     private final Object value;
226 
Only(Object value)227     public Only(Object value) {
228       this.value = checkNotNull(value, "value");
229     }
230 
matches(Object other)231     public boolean matches(Object other) {
232       return value.equals(other);
233     }
234 
equals(Object other)235     @Override public boolean equals(Object other) {
236       return other instanceof Only
237           && ((Only) other).value.equals(value);
238     }
239 
hashCode()240     @Override public int hashCode() {
241       return 37 * value.hashCode();
242     }
243 
toString()244     @Override public String toString() {
245       return "only(" + value + ")";
246     }
247 
248     private static final long serialVersionUID = 0;
249   }
250 
251   /**
252    * Returns a matcher which matches only the given object.
253    */
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>
259       implements Serializable {
260     private final Object value;
261 
IdenticalTo(Object value)262     public IdenticalTo(Object value) {
263       this.value = checkNotNull(value, "value");
264     }
265 
matches(Object other)266     public boolean matches(Object other) {
267       return value == other;
268     }
269 
equals(Object other)270     @Override public boolean equals(Object other) {
271       return other instanceof IdenticalTo
272           && ((IdenticalTo) other).value == value;
273     }
274 
hashCode()275     @Override public int hashCode() {
276       return 37 * System.identityHashCode(value);
277     }
278 
toString()279     @Override public String toString() {
280       return "identicalTo(" + value + ")";
281     }
282 
283     private static final long serialVersionUID = 0;
284   }
285 
286   /**
287    * Returns a matcher which matches classes in the given package. Packages are specific to their
288    * classloader, so classes with the same package name may not have the same package at runtime.
289    */
inPackage(final Package targetPackage)290   public static Matcher<Class> inPackage(final Package targetPackage) {
291     return new InPackage(targetPackage);
292   }
293 
294   private static class InPackage extends AbstractMatcher<Class> implements Serializable {
295     private final transient Package targetPackage;
296     private final String packageName;
297 
InPackage(Package targetPackage)298     public InPackage(Package targetPackage) {
299       this.targetPackage = checkNotNull(targetPackage, "package");
300       this.packageName = targetPackage.getName();
301     }
302 
matches(Class c)303     public boolean matches(Class c) {
304       return c.getPackage().equals(targetPackage);
305     }
306 
equals(Object other)307     @Override public boolean equals(Object other) {
308       return other instanceof InPackage
309           && ((InPackage) other).targetPackage.equals(targetPackage);
310     }
311 
hashCode()312     @Override public int hashCode() {
313       return 37 * targetPackage.hashCode();
314     }
315 
toString()316     @Override public String toString() {
317       return "inPackage(" + targetPackage.getName() + ")";
318     }
319 
readResolve()320     public Object readResolve() {
321       return inPackage(Package.getPackage(packageName));
322     }
323 
324     private static final long serialVersionUID = 0;
325   }
326 
327   /**
328    * Returns a matcher which matches classes in the given package and its subpackages. Unlike
329    * {@link #inPackage(Package) inPackage()}, this matches classes from any classloader.
330    *
331    * @since 2.0
332    */
inSubpackage(final String targetPackageName)333   public static Matcher<Class> inSubpackage(final String targetPackageName) {
334     return new InSubpackage(targetPackageName);
335   }
336 
337   private static class InSubpackage extends AbstractMatcher<Class> implements Serializable {
338     private final String targetPackageName;
339 
InSubpackage(String targetPackageName)340     public InSubpackage(String targetPackageName) {
341       this.targetPackageName = targetPackageName;
342     }
343 
matches(Class c)344     public boolean matches(Class c) {
345       String classPackageName = c.getPackage().getName();
346       return classPackageName.equals(targetPackageName)
347           || classPackageName.startsWith(targetPackageName + ".");
348     }
349 
equals(Object other)350     @Override public boolean equals(Object other) {
351       return other instanceof InSubpackage
352           && ((InSubpackage) other).targetPackageName.equals(targetPackageName);
353     }
354 
hashCode()355     @Override public int hashCode() {
356       return 37 * targetPackageName.hashCode();
357     }
358 
toString()359     @Override public String toString() {
360       return "inSubpackage(" + targetPackageName + ")";
361     }
362 
363     private static final long serialVersionUID = 0;
364   }
365 
366   /**
367    * Returns a matcher which matches methods with matching return types.
368    */
returns( final Matcher<? super Class<?>> returnType)369   public static Matcher<Method> returns(
370       final Matcher<? super Class<?>> returnType) {
371     return new Returns(returnType);
372   }
373 
374   private static class Returns extends AbstractMatcher<Method> implements Serializable {
375     private final Matcher<? super Class<?>> returnType;
376 
Returns(Matcher<? super Class<?>> returnType)377     public Returns(Matcher<? super Class<?>> returnType) {
378       this.returnType = checkNotNull(returnType, "return type matcher");
379     }
380 
matches(Method m)381     public boolean matches(Method m) {
382       return returnType.matches(m.getReturnType());
383     }
384 
equals(Object other)385     @Override public boolean equals(Object other) {
386       return other instanceof Returns
387           && ((Returns) other).returnType.equals(returnType);
388     }
389 
hashCode()390     @Override public int hashCode() {
391       return 37 * returnType.hashCode();
392     }
393 
toString()394     @Override public String toString() {
395       return "returns(" + returnType + ")";
396     }
397 
398     private static final long serialVersionUID = 0;
399   }
400 }
401