blob: 9cfdb77d36e7af6299a1da864521229b3855a0ea [file] [log] [blame]
crazyboblee66b415a2006-08-25 02:01:19 +00001/**
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
17package com.google.inject;
18
limpbizkit5789ef42008-08-04 06:44:30 +000019import com.google.inject.internal.Annotations;
20import com.google.inject.internal.MoreTypes;
limpbizkit53664a72009-02-21 00:25:27 +000021import static com.google.inject.internal.Preconditions.checkArgument;
22import static com.google.inject.internal.Preconditions.checkNotNull;
limpbizkit5789ef42008-08-04 06:44:30 +000023import com.google.inject.internal.ToStringBuilder;
crazyboblee4602a6f2007-02-15 02:45:18 +000024import java.lang.annotation.Annotation;
crazyboblee6ab7e1f2006-12-02 00:20:36 +000025import java.lang.reflect.Type;
crazyboblee6ab7e1f2006-12-02 00:20:36 +000026
crazyboblee66b415a2006-08-25 02:01:19 +000027/**
crazyboblee4602a6f2007-02-15 02:45:18 +000028 * Binding key consisting of an injection type and an optional annotation.
29 * Matches the type and annotation at a point of injection.
crazyboblee41bc8522006-12-08 07:06:55 +000030 *
crazyboblee61257a82007-03-03 00:23:40 +000031 * <p>For example, {@code Key.get(Service.class, Transactional.class)} will
crazyboblee4602a6f2007-02-15 02:45:18 +000032 * match:
crazyboblee41bc8522006-12-08 07:06:55 +000033 *
crazyboblee63b592b2007-01-25 02:45:24 +000034 * <pre>
crazyboblee4602a6f2007-02-15 02:45:18 +000035 * {@literal @}Inject
crazyboblee278ee4d2007-02-15 19:23:13 +000036 * public void setService({@literal @}Transactional Service service) {
crazyboblee41bc8522006-12-08 07:06:55 +000037 * ...
38 * }
crazyboblee63b592b2007-01-25 02:45:24 +000039 * </pre>
crazyboblee66b415a2006-08-25 02:01:19 +000040 *
crazyboblee4602a6f2007-02-15 02:45:18 +000041 * <p>{@code Key} supports generic types via subclassing just like {@link
42 * TypeLiteral}.
43 *
limpbizkitc0fe03b2008-06-02 04:46:53 +000044 * <p>Keys do not differentiate between primitive types (int, char, etc.) and
45 * their correpsonding wrapper types (Integer, Character, etc.). Primitive
46 * types will be replaced with their wrapper types when keys are created.
47 *
crazyboblee66b415a2006-08-25 02:01:19 +000048 * @author crazybob@google.com (Bob Lee)
49 */
limpbizkit6caa8dc2009-05-19 00:40:02 +000050public class Key<T> {
crazyboblee6ab7e1f2006-12-02 00:20:36 +000051
limpbizkitf530b252008-05-27 23:03:42 +000052 private final AnnotationStrategy annotationStrategy;
crazyboblee66b415a2006-08-25 02:01:19 +000053
limpbizkitf530b252008-05-27 23:03:42 +000054 private final TypeLiteral<T> typeLiteral;
55 private final int hashCode;
crazyboblee66b415a2006-08-25 02:01:19 +000056
crazybobleeed8825f2006-12-06 01:28:10 +000057 /**
58 * Constructs a new key. Derives the type from this class's type parameter.
crazyboblee41bc8522006-12-08 07:06:55 +000059 *
60 * <p>Clients create an empty anonymous subclass. Doing so embeds the type
kevinb9na99dca72007-02-11 04:48:57 +000061 * parameter in the anonymous class's type hierarchy so we can reconstitute it
62 * at runtime despite erasure.
crazybobleeed8825f2006-12-06 01:28:10 +000063 *
crazyboblee4602a6f2007-02-15 02:45:18 +000064 * <p>Example usage for a binding of type {@code Foo} annotated with
65 * {@code @Bar}:
66 *
67 * <p>{@code new Key<Foo>(Bar.class) {}}.
crazybobleeed8825f2006-12-06 01:28:10 +000068 */
kevinb9na99dca72007-02-11 04:48:57 +000069 @SuppressWarnings("unchecked")
crazyboblee4602a6f2007-02-15 02:45:18 +000070 protected Key(Class<? extends Annotation> annotationType) {
71 this.annotationStrategy = strategyFor(annotationType);
limpbizkit4272aef2008-11-23 08:10:09 +000072 this.typeLiteral = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass());
crazyboblee41bc8522006-12-08 07:06:55 +000073 this.hashCode = computeHashCode();
crazyboblee6ab7e1f2006-12-02 00:20:36 +000074 }
75
crazybobleeed8825f2006-12-06 01:28:10 +000076 /**
crazyboblee4602a6f2007-02-15 02:45:18 +000077 * Constructs a new key. Derives the type from this class's type parameter.
78 *
79 * <p>Clients create an empty anonymous subclass. Doing so embeds the type
80 * parameter in the anonymous class's type hierarchy so we can reconstitute it
81 * at runtime despite erasure.
82 *
83 * <p>Example usage for a binding of type {@code Foo} annotated with
84 * {@code @Bar}:
85 *
86 * <p>{@code new Key<Foo>(new Bar()) {}}.
crazybobleeed8825f2006-12-06 01:28:10 +000087 */
crazyboblee4602a6f2007-02-15 02:45:18 +000088 @SuppressWarnings("unchecked")
89 protected Key(Annotation annotation) {
kevinb9n225310e2007-02-20 04:12:01 +000090 // no usages, not test-covered
crazyboblee4602a6f2007-02-15 02:45:18 +000091 this.annotationStrategy = strategyFor(annotation);
limpbizkit4272aef2008-11-23 08:10:09 +000092 this.typeLiteral = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass());
crazyboblee4602a6f2007-02-15 02:45:18 +000093 this.hashCode = computeHashCode();
94 }
95
96 /**
97 * Constructs a new key. Derives the type from this class's type parameter.
98 *
99 * <p>Clients create an empty anonymous subclass. Doing so embeds the type
100 * parameter in the anonymous class's type hierarchy so we can reconstitute it
101 * at runtime despite erasure.
102 *
crazyboblee4602a6f2007-02-15 02:45:18 +0000103 * <p>Example usage for a binding of type {@code Foo}:
104 *
105 * <p>{@code new Key<Foo>() {}}.
106 */
107 @SuppressWarnings("unchecked")
crazyboblee6ab7e1f2006-12-02 00:20:36 +0000108 protected Key() {
limpbizkitf530b252008-05-27 23:03:42 +0000109 this.annotationStrategy = NullAnnotationStrategy.INSTANCE;
limpbizkit4272aef2008-11-23 08:10:09 +0000110 this.typeLiteral = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass());
crazyboblee4602a6f2007-02-15 02:45:18 +0000111 this.hashCode = computeHashCode();
crazyboblee6ab7e1f2006-12-02 00:20:36 +0000112 }
113
crazyboblee41bc8522006-12-08 07:06:55 +0000114 /**
115 * Unsafe. Constructs a key from a manually specified type.
116 */
kevinb9na99dca72007-02-11 04:48:57 +0000117 @SuppressWarnings("unchecked")
crazyboblee4602a6f2007-02-15 02:45:18 +0000118 private Key(Type type, AnnotationStrategy annotationStrategy) {
119 this.annotationStrategy = annotationStrategy;
limpbizkit4272aef2008-11-23 08:10:09 +0000120 this.typeLiteral = MoreTypes.makeKeySafe((TypeLiteral<T>) TypeLiteral.get(type));
crazyboblee41bc8522006-12-08 07:06:55 +0000121 this.hashCode = computeHashCode();
crazyboblee6ab7e1f2006-12-02 00:20:36 +0000122 }
123
kevinb9na99dca72007-02-11 04:48:57 +0000124 /** Constructs a key from a manually specified type. */
limpbizkit4272aef2008-11-23 08:10:09 +0000125 private Key(TypeLiteral<T> typeLiteral, AnnotationStrategy annotationStrategy) {
crazyboblee4602a6f2007-02-15 02:45:18 +0000126 this.annotationStrategy = annotationStrategy;
limpbizkit4272aef2008-11-23 08:10:09 +0000127 this.typeLiteral = MoreTypes.makeKeySafe(typeLiteral);
crazyboblee41bc8522006-12-08 07:06:55 +0000128 this.hashCode = computeHashCode();
crazyboblee66b415a2006-08-25 02:01:19 +0000129 }
130
crazyboblee41bc8522006-12-08 07:06:55 +0000131 private int computeHashCode() {
crazyboblee4602a6f2007-02-15 02:45:18 +0000132 return typeLiteral.hashCode() * 31 + annotationStrategy.hashCode();
crazybobleeb9446682006-12-11 07:16:41 +0000133 }
134
135 /**
crazyboblee0baa9fc2007-01-31 02:38:54 +0000136 * Gets the key type.
crazybobleeed8825f2006-12-06 01:28:10 +0000137 */
limpbizkitf530b252008-05-27 23:03:42 +0000138 public final TypeLiteral<T> getTypeLiteral() {
crazyboblee0baa9fc2007-01-31 02:38:54 +0000139 return typeLiteral;
crazybobleeed8825f2006-12-06 01:28:10 +0000140 }
141
142 /**
crazyboblee4602a6f2007-02-15 02:45:18 +0000143 * Gets the annotation type.
crazybobleeed8825f2006-12-06 01:28:10 +0000144 */
limpbizkitf530b252008-05-27 23:03:42 +0000145 public final Class<? extends Annotation> getAnnotationType() {
crazyboblee4602a6f2007-02-15 02:45:18 +0000146 return annotationStrategy.getAnnotationType();
147 }
148
crazybobleed7908e82007-02-16 01:04:53 +0000149 /**
150 * Gets the annotation.
151 */
limpbizkitf530b252008-05-27 23:03:42 +0000152 public final Annotation getAnnotation() {
crazybobleed7908e82007-02-16 01:04:53 +0000153 return annotationStrategy.getAnnotation();
154 }
155
crazyboblee4602a6f2007-02-15 02:45:18 +0000156 boolean hasAnnotationType() {
157 return annotationStrategy.getAnnotationType() != null;
158 }
159
160 String getAnnotationName() {
161 Annotation annotation = annotationStrategy.getAnnotation();
162 if (annotation != null) {
163 return annotation.toString();
164 }
165
kevinb9n225310e2007-02-20 04:12:01 +0000166 // not test-covered
crazyboblee4602a6f2007-02-15 02:45:18 +0000167 return annotationStrategy.getAnnotationType().toString();
crazyboblee66b415a2006-08-25 02:01:19 +0000168 }
169
crazybobleef1ba2b52007-01-29 21:19:53 +0000170 Class<? super T> getRawType() {
crazyboblee0baa9fc2007-01-31 02:38:54 +0000171 return typeLiteral.getRawType();
crazybobleed42a05b2006-12-07 01:00:33 +0000172 }
173
crazyboblee552472f2007-09-07 16:52:39 +0000174 /**
175 * Gets the key of this key's provider.
176 */
177 Key<Provider<T>> providerKey() {
178 return ofType(typeLiteral.providerType());
179 }
180
limpbizkitf530b252008-05-27 23:03:42 +0000181 @Override public final boolean equals(Object o) {
crazyboblee66b415a2006-08-25 02:01:19 +0000182 if (o == this) {
183 return true;
184 }
crazyboblee41bc8522006-12-08 07:06:55 +0000185 if (!(o instanceof Key<?>)) {
crazybobleeed8825f2006-12-06 01:28:10 +0000186 return false;
187 }
crazyboblee41bc8522006-12-08 07:06:55 +0000188 Key<?> other = (Key<?>) o;
crazyboblee4602a6f2007-02-15 02:45:18 +0000189 return annotationStrategy.equals(other.annotationStrategy)
190 && typeLiteral.equals(other.typeLiteral);
crazyboblee66b415a2006-08-25 02:01:19 +0000191 }
192
limpbizkitf530b252008-05-27 23:03:42 +0000193 @Override public final int hashCode() {
194 return this.hashCode;
195 }
196
197 @Override public final String toString() {
crazyboblee4602a6f2007-02-15 02:45:18 +0000198 return new ToStringBuilder(Key.class)
199 .add("type", typeLiteral)
200 .add("annotation", annotationStrategy)
201 .toString();
crazyboblee66b415a2006-08-25 02:01:19 +0000202 }
203
crazyboblee6ab7e1f2006-12-02 00:20:36 +0000204 /**
crazyboblee4602a6f2007-02-15 02:45:18 +0000205 * Gets a key for an injection type and an annotation strategy.
206 */
207 static <T> Key<T> get(Class<T> type,
208 AnnotationStrategy annotationStrategy) {
limpbizkitf530b252008-05-27 23:03:42 +0000209 return new Key<T>(type, annotationStrategy);
crazyboblee4602a6f2007-02-15 02:45:18 +0000210 }
211
212 /**
213 * Gets a key for an injection type.
crazyboblee6ab7e1f2006-12-02 00:20:36 +0000214 */
crazyboblee41bc8522006-12-08 07:06:55 +0000215 public static <T> Key<T> get(Class<T> type) {
limpbizkitf530b252008-05-27 23:03:42 +0000216 return new Key<T>(type, NullAnnotationStrategy.INSTANCE);
crazyboblee6ab7e1f2006-12-02 00:20:36 +0000217 }
218
219 /**
crazyboblee4602a6f2007-02-15 02:45:18 +0000220 * Gets a key for an injection type and an annotation type.
221 */
222 public static <T> Key<T> get(Class<T> type,
223 Class<? extends Annotation> annotationType) {
limpbizkitf530b252008-05-27 23:03:42 +0000224 return new Key<T>(type, strategyFor(annotationType));
crazyboblee4602a6f2007-02-15 02:45:18 +0000225 }
226
227 /**
crazyboblee4602a6f2007-02-15 02:45:18 +0000228 * Gets a key for an injection type and an annotation.
229 */
230 public static <T> Key<T> get(Class<T> type, Annotation annotation) {
limpbizkitf530b252008-05-27 23:03:42 +0000231 return new Key<T>(type, strategyFor(annotation));
crazyboblee4602a6f2007-02-15 02:45:18 +0000232 }
233
234 /**
235 * Gets a key for an injection type.
crazybobleeed8825f2006-12-06 01:28:10 +0000236 */
crazyboblee41bc8522006-12-08 07:06:55 +0000237 public static Key<?> get(Type type) {
limpbizkitf530b252008-05-27 23:03:42 +0000238 return new Key<Object>(type, NullAnnotationStrategy.INSTANCE);
crazybobleeed8825f2006-12-06 01:28:10 +0000239 }
240
241 /**
crazyboblee4602a6f2007-02-15 02:45:18 +0000242 * Gets a key for an injection type and an annotation type.
243 */
244 public static Key<?> get(Type type,
245 Class<? extends Annotation> annotationType) {
limpbizkitf530b252008-05-27 23:03:42 +0000246 return new Key<Object>(type, strategyFor(annotationType));
crazyboblee4602a6f2007-02-15 02:45:18 +0000247 }
248
249 /**
250 * Gets a key for an injection type and an annotation.
251 */
252 public static Key<?> get(Type type, Annotation annotation) {
limpbizkitf530b252008-05-27 23:03:42 +0000253 return new Key<Object>(type, strategyFor(annotation));
crazyboblee4602a6f2007-02-15 02:45:18 +0000254 }
255
256 /**
crazyboblee4602a6f2007-02-15 02:45:18 +0000257 * Gets a key for an injection type.
crazyboblee41bc8522006-12-08 07:06:55 +0000258 */
crazyboblee0baa9fc2007-01-31 02:38:54 +0000259 public static <T> Key<T> get(TypeLiteral<T> typeLiteral) {
limpbizkitf530b252008-05-27 23:03:42 +0000260 return new Key<T>(typeLiteral, NullAnnotationStrategy.INSTANCE);
crazyboblee41bc8522006-12-08 07:06:55 +0000261 }
262
263 /**
crazyboblee4602a6f2007-02-15 02:45:18 +0000264 * Gets a key for an injection type and an annotation type.
265 */
266 public static <T> Key<T> get(TypeLiteral<T> typeLiteral,
267 Class<? extends Annotation> annotationType) {
limpbizkitf530b252008-05-27 23:03:42 +0000268 return new Key<T>(typeLiteral, strategyFor(annotationType));
crazyboblee4602a6f2007-02-15 02:45:18 +0000269 }
270
271 /**
272 * Gets a key for an injection type and an annotation.
273 */
274 public static <T> Key<T> get(TypeLiteral<T> typeLiteral,
275 Annotation annotation) {
limpbizkitf530b252008-05-27 23:03:42 +0000276 return new Key<T>(typeLiteral, strategyFor(annotation));
crazyboblee4602a6f2007-02-15 02:45:18 +0000277 }
278
279 /**
crazyboblee4602a6f2007-02-15 02:45:18 +0000280 * Returns a new key of the specified type with the same annotation as this
281 * key.
282 */
limpbizkit5ae41eb2009-06-06 17:51:27 +0000283 public <T> Key<T> ofType(Class<T> type) {
limpbizkitf530b252008-05-27 23:03:42 +0000284 return new Key<T>(type, annotationStrategy);
crazyboblee4602a6f2007-02-15 02:45:18 +0000285 }
286
287 /**
288 * Returns a new key of the specified type with the same annotation as this
289 * key.
290 */
limpbizkit5ae41eb2009-06-06 17:51:27 +0000291 public Key<?> ofType(Type type) {
limpbizkitf530b252008-05-27 23:03:42 +0000292 return new Key<Object>(type, annotationStrategy);
crazyboblee4602a6f2007-02-15 02:45:18 +0000293 }
294
crazybobleec3e88492007-02-25 22:36:58 +0000295 /**
crazyboblee552472f2007-09-07 16:52:39 +0000296 * Returns a new key of the specified type with the same annotation as this
297 * key.
298 */
299 <T> Key<T> ofType(TypeLiteral<T> type) {
limpbizkitf530b252008-05-27 23:03:42 +0000300 return new Key<T>(type, annotationStrategy);
crazyboblee552472f2007-09-07 16:52:39 +0000301 }
302
303 /**
crazybobleec3e88492007-02-25 22:36:58 +0000304 * Returns true if this key has annotation attributes.
crazybobleec3e88492007-02-25 22:36:58 +0000305 */
limpbizkit5ae41eb2009-06-06 17:51:27 +0000306 public boolean hasAttributes() {
crazybobleec3e88492007-02-25 22:36:58 +0000307 return annotationStrategy.hasAttributes();
308 }
309
310 /**
311 * Returns this key without annotation attributes, i.e. with only the
312 * annotation type.
313 */
limpbizkit5ae41eb2009-06-06 17:51:27 +0000314 public Key<T> withoutAttributes() {
limpbizkitf530b252008-05-27 23:03:42 +0000315 return new Key<T>(typeLiteral, annotationStrategy.withoutAttributes());
crazyboblee4602a6f2007-02-15 02:45:18 +0000316 }
317
limpbizkit6caa8dc2009-05-19 00:40:02 +0000318 interface AnnotationStrategy {
crazyboblee4602a6f2007-02-15 02:45:18 +0000319 Annotation getAnnotation();
320 Class<? extends Annotation> getAnnotationType();
crazybobleec3e88492007-02-25 22:36:58 +0000321 boolean hasAttributes();
322 AnnotationStrategy withoutAttributes();
crazyboblee4602a6f2007-02-15 02:45:18 +0000323 }
324
crazyboblee4602a6f2007-02-15 02:45:18 +0000325 /**
326 * Returns {@code true} if the given annotation type has no attributes.
327 */
328 static boolean isMarker(Class<? extends Annotation> annotationType) {
329 return annotationType.getDeclaredMethods().length == 0;
330 }
331
332 /**
333 * Gets the strategy for an annotation.
334 */
335 static AnnotationStrategy strategyFor(Annotation annotation) {
kevinb9n1601ae52008-06-03 22:21:04 +0000336 checkNotNull(annotation, "annotation");
crazyboblee0f09fe32007-02-23 23:43:57 +0000337 Class<? extends Annotation> annotationType = annotation.annotationType();
338 ensureRetainedAtRuntime(annotationType);
crazybobleec3e88492007-02-25 22:36:58 +0000339 ensureIsBindingAnnotation(annotationType);
crazyboblee81303cd2007-05-09 00:44:37 +0000340
341 if (annotationType.getDeclaredMethods().length == 0) {
342 return new AnnotationTypeStrategy(annotationType, annotation);
343 }
344
crazybobleec3e88492007-02-25 22:36:58 +0000345 return new AnnotationInstanceStrategy(annotation);
crazyboblee4602a6f2007-02-15 02:45:18 +0000346 }
347
348 /**
349 * Gets the strategy for an annotation type.
350 */
kevinb9n1601ae52008-06-03 22:21:04 +0000351 static AnnotationStrategy strategyFor(Class<? extends Annotation> annotationType) {
352 checkNotNull(annotationType, "annotation type");
crazyboblee0f09fe32007-02-23 23:43:57 +0000353 ensureRetainedAtRuntime(annotationType);
crazybobleec3e88492007-02-25 22:36:58 +0000354 ensureIsBindingAnnotation(annotationType);
crazyboblee4602a6f2007-02-15 02:45:18 +0000355 return new AnnotationTypeStrategy(annotationType, null);
356 }
357
crazyboblee0f09fe32007-02-23 23:43:57 +0000358 private static void ensureRetainedAtRuntime(
359 Class<? extends Annotation> annotationType) {
limpbizkit5789ef42008-08-04 06:44:30 +0000360 checkArgument(Annotations.isRetainedAtRuntime(annotationType),
361 "%s is not retained at runtime. Please annotate it with @Retention(RUNTIME).",
362 annotationType.getName());
crazyboblee0f09fe32007-02-23 23:43:57 +0000363 }
364
crazybobleec3e88492007-02-25 22:36:58 +0000365 private static void ensureIsBindingAnnotation(
366 Class<? extends Annotation> annotationType) {
limpbizkit5789ef42008-08-04 06:44:30 +0000367 checkArgument(isBindingAnnotation(annotationType),
368 "%s is not a binding annotation. Please annotate it with @BindingAnnotation.",
369 annotationType.getName());
crazybobleec3e88492007-02-25 22:36:58 +0000370 }
371
limpbizkitf530b252008-05-27 23:03:42 +0000372 static enum NullAnnotationStrategy implements AnnotationStrategy {
373 INSTANCE;
374
375 public boolean hasAttributes() {
376 return false;
377 }
378
379 public AnnotationStrategy withoutAttributes() {
380 throw new UnsupportedOperationException("Key already has no attributes.");
381 }
382
383 public Annotation getAnnotation() {
384 return null;
385 }
386
387 public Class<? extends Annotation> getAnnotationType() {
388 return null;
389 }
390
391 @Override public String toString() {
392 return "[none]";
393 }
394 }
395
kevinb9n225310e2007-02-20 04:12:01 +0000396 // this class not test-covered
crazyboblee4602a6f2007-02-15 02:45:18 +0000397 static class AnnotationInstanceStrategy implements AnnotationStrategy {
398
399 final Annotation annotation;
400
401 AnnotationInstanceStrategy(Annotation annotation) {
kevinb9n1601ae52008-06-03 22:21:04 +0000402 this.annotation = checkNotNull(annotation, "annotation");
crazyboblee4602a6f2007-02-15 02:45:18 +0000403 }
404
crazybobleec3e88492007-02-25 22:36:58 +0000405 public boolean hasAttributes() {
406 return true;
407 }
408
409 public AnnotationStrategy withoutAttributes() {
410 return new AnnotationTypeStrategy(getAnnotationType(), annotation);
411 }
412
crazyboblee4602a6f2007-02-15 02:45:18 +0000413 public Annotation getAnnotation() {
414 return annotation;
415 }
416
417 public Class<? extends Annotation> getAnnotationType() {
418 return annotation.annotationType();
419 }
420
limpbizkitf530b252008-05-27 23:03:42 +0000421 @Override public boolean equals(Object o) {
crazyboblee4602a6f2007-02-15 02:45:18 +0000422 if (!(o instanceof AnnotationInstanceStrategy)) {
423 return false;
424 }
425
426 AnnotationInstanceStrategy other = (AnnotationInstanceStrategy) o;
427 return annotation.equals(other.annotation);
428 }
429
limpbizkitf530b252008-05-27 23:03:42 +0000430 @Override public int hashCode() {
crazyboblee4602a6f2007-02-15 02:45:18 +0000431 return annotation.hashCode();
432 }
433
limpbizkitf530b252008-05-27 23:03:42 +0000434 @Override public String toString() {
crazyboblee4602a6f2007-02-15 02:45:18 +0000435 return annotation.toString();
436 }
437 }
438
439 static class AnnotationTypeStrategy implements AnnotationStrategy {
440
441 final Class<? extends Annotation> annotationType;
442
443 // Keep the instance around if we have it so the client can request it.
444 final Annotation annotation;
445
446 AnnotationTypeStrategy(Class<? extends Annotation> annotationType,
447 Annotation annotation) {
kevinb9n1601ae52008-06-03 22:21:04 +0000448 this.annotationType = checkNotNull(annotationType, "annotation type");
crazyboblee4602a6f2007-02-15 02:45:18 +0000449 this.annotation = annotation;
450 }
451
crazybobleec3e88492007-02-25 22:36:58 +0000452 public boolean hasAttributes() {
453 return false;
454 }
455
456 public AnnotationStrategy withoutAttributes() {
457 throw new UnsupportedOperationException("Key already has no attributes.");
458 }
459
crazyboblee4602a6f2007-02-15 02:45:18 +0000460 public Annotation getAnnotation() {
461 return annotation;
462 }
463
464 public Class<? extends Annotation> getAnnotationType() {
465 return annotationType;
466 }
467
limpbizkitf530b252008-05-27 23:03:42 +0000468 @Override public boolean equals(Object o) {
crazyboblee4602a6f2007-02-15 02:45:18 +0000469 if (!(o instanceof AnnotationTypeStrategy)) {
470 return false;
471 }
472
473 AnnotationTypeStrategy other = (AnnotationTypeStrategy) o;
474 return annotationType.equals(other.annotationType);
475 }
476
limpbizkitf530b252008-05-27 23:03:42 +0000477 @Override public int hashCode() {
crazyboblee4602a6f2007-02-15 02:45:18 +0000478 return annotationType.hashCode();
479 }
480
limpbizkitf530b252008-05-27 23:03:42 +0000481 @Override public String toString() {
crazybobleed7908e82007-02-16 01:04:53 +0000482 return "@" + annotationType.getName();
crazyboblee41bc8522006-12-08 07:06:55 +0000483 }
crazybobleeed8825f2006-12-06 01:28:10 +0000484 }
crazybobleec3e88492007-02-25 22:36:58 +0000485
486 static boolean isBindingAnnotation(Annotation annotation) {
487 return isBindingAnnotation(annotation.annotationType());
488 }
489
490 static boolean isBindingAnnotation(
491 Class<? extends Annotation> annotationType) {
492 return annotationType.isAnnotationPresent(BindingAnnotation.class);
493 }
crazyboblee66b415a2006-08-25 02:01:19 +0000494}