blob: b96822a367f0add0f988599c5366982c13b69317 [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
limpbizkite4647a62008-05-25 18:03:35 +000019import com.google.inject.internal.Annotations;
kevinb9ncad2c2b2007-05-15 17:28:03 +000020import static com.google.inject.internal.Objects.nonNull;
limpbizkite4647a62008-05-25 18:03:35 +000021import com.google.inject.internal.ToStringBuilder;
limpbizkit916f5482008-04-16 20:51:14 +000022
limpbizkite4647a62008-05-25 18:03:35 +000023import java.io.Serializable;
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 *
crazyboblee66b415a2006-08-25 02:01:19 +000044 * @author crazybob@google.com (Bob Lee)
45 */
limpbizkitf530b252008-05-27 23:03:42 +000046public class Key<T> implements Serializable {
crazyboblee6ab7e1f2006-12-02 00:20:36 +000047
limpbizkitf530b252008-05-27 23:03:42 +000048 private final AnnotationStrategy annotationStrategy;
crazyboblee66b415a2006-08-25 02:01:19 +000049
limpbizkitf530b252008-05-27 23:03:42 +000050 private final TypeLiteral<T> typeLiteral;
51 private final int hashCode;
crazyboblee66b415a2006-08-25 02:01:19 +000052
crazybobleeed8825f2006-12-06 01:28:10 +000053 /**
54 * Constructs a new key. Derives the type from this class's type parameter.
crazyboblee41bc8522006-12-08 07:06:55 +000055 *
56 * <p>Clients create an empty anonymous subclass. Doing so embeds the type
kevinb9na99dca72007-02-11 04:48:57 +000057 * parameter in the anonymous class's type hierarchy so we can reconstitute it
58 * at runtime despite erasure.
crazybobleeed8825f2006-12-06 01:28:10 +000059 *
crazyboblee4602a6f2007-02-15 02:45:18 +000060 * <p>Example usage for a binding of type {@code Foo} annotated with
61 * {@code @Bar}:
62 *
63 * <p>{@code new Key<Foo>(Bar.class) {}}.
crazybobleeed8825f2006-12-06 01:28:10 +000064 */
kevinb9na99dca72007-02-11 04:48:57 +000065 @SuppressWarnings("unchecked")
crazyboblee4602a6f2007-02-15 02:45:18 +000066 protected Key(Class<? extends Annotation> annotationType) {
67 this.annotationStrategy = strategyFor(annotationType);
kevinb9na99dca72007-02-11 04:48:57 +000068 this.typeLiteral
69 = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass());
crazyboblee41bc8522006-12-08 07:06:55 +000070 this.hashCode = computeHashCode();
crazyboblee6ab7e1f2006-12-02 00:20:36 +000071 }
72
crazybobleeed8825f2006-12-06 01:28:10 +000073 /**
crazyboblee4602a6f2007-02-15 02:45:18 +000074 * Constructs a new key. Derives the type from this class's type parameter.
75 *
76 * <p>Clients create an empty anonymous subclass. Doing so embeds the type
77 * parameter in the anonymous class's type hierarchy so we can reconstitute it
78 * at runtime despite erasure.
79 *
80 * <p>Example usage for a binding of type {@code Foo} annotated with
81 * {@code @Bar}:
82 *
83 * <p>{@code new Key<Foo>(new Bar()) {}}.
crazybobleeed8825f2006-12-06 01:28:10 +000084 */
crazyboblee4602a6f2007-02-15 02:45:18 +000085 @SuppressWarnings("unchecked")
86 protected Key(Annotation annotation) {
kevinb9n225310e2007-02-20 04:12:01 +000087 // no usages, not test-covered
crazyboblee4602a6f2007-02-15 02:45:18 +000088 this.annotationStrategy = strategyFor(annotation);
89 this.typeLiteral
90 = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass());
91 this.hashCode = computeHashCode();
92 }
93
94 /**
95 * Constructs a new key. Derives the type from this class's type parameter.
96 *
97 * <p>Clients create an empty anonymous subclass. Doing so embeds the type
98 * parameter in the anonymous class's type hierarchy so we can reconstitute it
99 * at runtime despite erasure.
100 *
crazyboblee4602a6f2007-02-15 02:45:18 +0000101 * <p>Example usage for a binding of type {@code Foo}:
102 *
103 * <p>{@code new Key<Foo>() {}}.
104 */
105 @SuppressWarnings("unchecked")
crazyboblee6ab7e1f2006-12-02 00:20:36 +0000106 protected Key() {
limpbizkitf530b252008-05-27 23:03:42 +0000107 this.annotationStrategy = NullAnnotationStrategy.INSTANCE;
crazyboblee4602a6f2007-02-15 02:45:18 +0000108 this.typeLiteral
109 = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass());
110 this.hashCode = computeHashCode();
crazyboblee6ab7e1f2006-12-02 00:20:36 +0000111 }
112
crazyboblee41bc8522006-12-08 07:06:55 +0000113 /**
114 * Unsafe. Constructs a key from a manually specified type.
115 */
kevinb9na99dca72007-02-11 04:48:57 +0000116 @SuppressWarnings("unchecked")
crazyboblee4602a6f2007-02-15 02:45:18 +0000117 private Key(Type type, AnnotationStrategy annotationStrategy) {
118 this.annotationStrategy = annotationStrategy;
crazyboblee0baa9fc2007-01-31 02:38:54 +0000119 this.typeLiteral = (TypeLiteral<T>) TypeLiteral.get(type);
crazyboblee41bc8522006-12-08 07:06:55 +0000120 this.hashCode = computeHashCode();
crazyboblee6ab7e1f2006-12-02 00:20:36 +0000121 }
122
kevinb9na99dca72007-02-11 04:48:57 +0000123 /** Constructs a key from a manually specified type. */
crazyboblee4602a6f2007-02-15 02:45:18 +0000124 private Key(TypeLiteral<T> typeLiteral,
125 AnnotationStrategy annotationStrategy) {
126 this.annotationStrategy = annotationStrategy;
crazyboblee0baa9fc2007-01-31 02:38:54 +0000127 this.typeLiteral = 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 */
crazybobleedb395b22007-02-18 05:09:15 +0000283 <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 */
crazybobleedb395b22007-02-18 05:09:15 +0000291 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 */
306 boolean hasAttributes() {
307 return annotationStrategy.hasAttributes();
308 }
309
310 /**
311 * Returns this key without annotation attributes, i.e. with only the
312 * annotation type.
313 */
314 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
limpbizkite4647a62008-05-25 18:03:35 +0000318 interface AnnotationStrategy extends Serializable {
crazyboblee4602a6f2007-02-15 02:45:18 +0000319
320 Annotation getAnnotation();
321 Class<? extends Annotation> getAnnotationType();
crazybobleec3e88492007-02-25 22:36:58 +0000322 boolean hasAttributes();
323 AnnotationStrategy withoutAttributes();
crazyboblee4602a6f2007-02-15 02:45:18 +0000324 }
325
crazyboblee4602a6f2007-02-15 02:45:18 +0000326 /**
327 * Returns {@code true} if the given annotation type has no attributes.
328 */
329 static boolean isMarker(Class<? extends Annotation> annotationType) {
330 return annotationType.getDeclaredMethods().length == 0;
331 }
332
333 /**
334 * Gets the strategy for an annotation.
335 */
336 static AnnotationStrategy strategyFor(Annotation annotation) {
337 nonNull(annotation, "annotation");
crazyboblee0f09fe32007-02-23 23:43:57 +0000338 Class<? extends Annotation> annotationType = annotation.annotationType();
339 ensureRetainedAtRuntime(annotationType);
crazybobleec3e88492007-02-25 22:36:58 +0000340 ensureIsBindingAnnotation(annotationType);
crazyboblee81303cd2007-05-09 00:44:37 +0000341
342 if (annotationType.getDeclaredMethods().length == 0) {
343 return new AnnotationTypeStrategy(annotationType, annotation);
344 }
345
crazybobleec3e88492007-02-25 22:36:58 +0000346 return new AnnotationInstanceStrategy(annotation);
crazyboblee4602a6f2007-02-15 02:45:18 +0000347 }
348
349 /**
350 * Gets the strategy for an annotation type.
351 */
352 static AnnotationStrategy strategyFor(
353 Class<? extends Annotation> annotationType) {
354 nonNull(annotationType, "annotation type");
crazyboblee0f09fe32007-02-23 23:43:57 +0000355 ensureRetainedAtRuntime(annotationType);
crazybobleec3e88492007-02-25 22:36:58 +0000356 ensureIsBindingAnnotation(annotationType);
crazyboblee4602a6f2007-02-15 02:45:18 +0000357 return new AnnotationTypeStrategy(annotationType, null);
358 }
359
crazyboblee0f09fe32007-02-23 23:43:57 +0000360 private static void ensureRetainedAtRuntime(
361 Class<? extends Annotation> annotationType) {
362 if (!Annotations.isRetainedAtRuntime(annotationType)) {
363 throw new IllegalArgumentException(annotationType.getName()
364 + " is not retained at runtime."
365 + " Please annotate it with @Retention(RUNTIME).");
366 }
367 }
368
crazybobleec3e88492007-02-25 22:36:58 +0000369 private static void ensureIsBindingAnnotation(
370 Class<? extends Annotation> annotationType) {
371 if (!isBindingAnnotation(annotationType)) {
372 throw new IllegalArgumentException(annotationType.getName()
373 + " is not a binding annotation."
374 + " Please annotate it with @BindingAnnotation.");
375 }
376 }
377
limpbizkitf530b252008-05-27 23:03:42 +0000378 static enum NullAnnotationStrategy implements AnnotationStrategy {
379 INSTANCE;
380
381 public boolean hasAttributes() {
382 return false;
383 }
384
385 public AnnotationStrategy withoutAttributes() {
386 throw new UnsupportedOperationException("Key already has no attributes.");
387 }
388
389 public Annotation getAnnotation() {
390 return null;
391 }
392
393 public Class<? extends Annotation> getAnnotationType() {
394 return null;
395 }
396
397 @Override public String toString() {
398 return "[none]";
399 }
400 }
401
kevinb9n225310e2007-02-20 04:12:01 +0000402 // this class not test-covered
crazyboblee4602a6f2007-02-15 02:45:18 +0000403 static class AnnotationInstanceStrategy implements AnnotationStrategy {
404
405 final Annotation annotation;
406
407 AnnotationInstanceStrategy(Annotation annotation) {
408 this.annotation = nonNull(annotation, "annotation");
409 }
410
crazybobleec3e88492007-02-25 22:36:58 +0000411 public boolean hasAttributes() {
412 return true;
413 }
414
415 public AnnotationStrategy withoutAttributes() {
416 return new AnnotationTypeStrategy(getAnnotationType(), annotation);
417 }
418
crazyboblee4602a6f2007-02-15 02:45:18 +0000419 public Annotation getAnnotation() {
420 return annotation;
421 }
422
423 public Class<? extends Annotation> getAnnotationType() {
424 return annotation.annotationType();
425 }
426
limpbizkitf530b252008-05-27 23:03:42 +0000427 @Override public boolean equals(Object o) {
crazyboblee4602a6f2007-02-15 02:45:18 +0000428 if (!(o instanceof AnnotationInstanceStrategy)) {
429 return false;
430 }
431
432 AnnotationInstanceStrategy other = (AnnotationInstanceStrategy) o;
433 return annotation.equals(other.annotation);
434 }
435
limpbizkitf530b252008-05-27 23:03:42 +0000436 @Override public int hashCode() {
crazyboblee4602a6f2007-02-15 02:45:18 +0000437 return annotation.hashCode();
438 }
439
limpbizkitf530b252008-05-27 23:03:42 +0000440 @Override public String toString() {
crazyboblee4602a6f2007-02-15 02:45:18 +0000441 return annotation.toString();
442 }
limpbizkite4647a62008-05-25 18:03:35 +0000443
444 private static final long serialVersionUID = 0;
crazyboblee4602a6f2007-02-15 02:45:18 +0000445 }
446
447 static class AnnotationTypeStrategy implements AnnotationStrategy {
448
449 final Class<? extends Annotation> annotationType;
450
451 // Keep the instance around if we have it so the client can request it.
452 final Annotation annotation;
453
454 AnnotationTypeStrategy(Class<? extends Annotation> annotationType,
455 Annotation annotation) {
456 this.annotationType = nonNull(annotationType, "annotation type");
457 this.annotation = annotation;
458 }
459
crazybobleec3e88492007-02-25 22:36:58 +0000460 public boolean hasAttributes() {
461 return false;
462 }
463
464 public AnnotationStrategy withoutAttributes() {
465 throw new UnsupportedOperationException("Key already has no attributes.");
466 }
467
crazyboblee4602a6f2007-02-15 02:45:18 +0000468 public Annotation getAnnotation() {
469 return annotation;
470 }
471
472 public Class<? extends Annotation> getAnnotationType() {
473 return annotationType;
474 }
475
limpbizkitf530b252008-05-27 23:03:42 +0000476 @Override public boolean equals(Object o) {
crazyboblee4602a6f2007-02-15 02:45:18 +0000477 if (!(o instanceof AnnotationTypeStrategy)) {
478 return false;
479 }
480
481 AnnotationTypeStrategy other = (AnnotationTypeStrategy) o;
482 return annotationType.equals(other.annotationType);
483 }
484
limpbizkitf530b252008-05-27 23:03:42 +0000485 @Override public int hashCode() {
crazyboblee4602a6f2007-02-15 02:45:18 +0000486 return annotationType.hashCode();
487 }
488
limpbizkitf530b252008-05-27 23:03:42 +0000489 @Override public String toString() {
crazybobleed7908e82007-02-16 01:04:53 +0000490 return "@" + annotationType.getName();
crazyboblee41bc8522006-12-08 07:06:55 +0000491 }
limpbizkite4647a62008-05-25 18:03:35 +0000492
493 private static final long serialVersionUID = 0;
crazybobleeed8825f2006-12-06 01:28:10 +0000494 }
crazybobleec3e88492007-02-25 22:36:58 +0000495
496 static boolean isBindingAnnotation(Annotation annotation) {
497 return isBindingAnnotation(annotation.annotationType());
498 }
499
500 static boolean isBindingAnnotation(
501 Class<? extends Annotation> annotationType) {
502 return annotationType.isAnnotationPresent(BindingAnnotation.class);
503 }
limpbizkite4647a62008-05-25 18:03:35 +0000504
limpbizkitf530b252008-05-27 23:03:42 +0000505 /**
506 * Returns the canonical form of this key for serialization. The returned
507 * instance is always a {@code Key}, never a subclass. This prevents problems
508 * caused by serializing anonymous types.
509 */
510 protected final Object writeReplace() {
511 return getClass() == Key.class
512 ? this
513 : new Key<T>(typeLiteral, annotationStrategy);
514 }
515
limpbizkite4647a62008-05-25 18:03:35 +0000516 private static final long serialVersionUID = 0;
crazyboblee66b415a2006-08-25 02:01:19 +0000517}