001: /**
002: * Copyright (C) 2006 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */package com.google.inject;
016:
017: import static com.google.inject.util.Objects.nonNull;
018: import com.google.inject.util.StackTraceElements;
019: import com.google.inject.util.ToStringBuilder;
020: import com.google.inject.util.Annotations;
021: import java.lang.annotation.Annotation;
022: import java.lang.reflect.Member;
023: import java.lang.reflect.Type;
024:
025: /**
026: * Binding key consisting of an injection type and an optional annotation.
027: * Matches the type and annotation at a point of injection.
028: *
029: * <p>For example, {@code Key.get(Service.class, Transactional.class)} will
030: * match:
031: *
032: * <pre>
033: * {@literal @}Inject
034: * public void setService({@literal @}Transactional Service service) {
035: * ...
036: * }
037: * </pre>
038: *
039: * <p>{@code Key} supports generic types via subclassing just like {@link
040: * TypeLiteral}.
041: *
042: * @author crazybob@google.com (Bob Lee)
043: */
044: public abstract class Key<T> {
045:
046: final AnnotationStrategy annotationStrategy;
047:
048: final TypeLiteral<T> typeLiteral;
049: final int hashCode;
050:
051: /**
052: * Constructs a new key. Derives the type from this class's type parameter.
053: *
054: * <p>Clients create an empty anonymous subclass. Doing so embeds the type
055: * parameter in the anonymous class's type hierarchy so we can reconstitute it
056: * at runtime despite erasure.
057: *
058: * <p>Example usage for a binding of type {@code Foo} annotated with
059: * {@code @Bar}:
060: *
061: * <p>{@code new Key<Foo>(Bar.class) {}}.
062: */
063: @SuppressWarnings("unchecked")
064: protected Key(Class<? extends Annotation> annotationType) {
065: this .annotationStrategy = strategyFor(annotationType);
066: this .typeLiteral = (TypeLiteral<T>) TypeLiteral
067: .fromSuperclassTypeParameter(getClass());
068: this .hashCode = computeHashCode();
069: }
070:
071: /**
072: * Constructs a new key. Derives the type from this class's type parameter.
073: *
074: * <p>Clients create an empty anonymous subclass. Doing so embeds the type
075: * parameter in the anonymous class's type hierarchy so we can reconstitute it
076: * at runtime despite erasure.
077: *
078: * <p>Example usage for a binding of type {@code Foo} annotated with
079: * {@code @Bar}:
080: *
081: * <p>{@code new Key<Foo>(new Bar()) {}}.
082: */
083: @SuppressWarnings("unchecked")
084: protected Key(Annotation annotation) {
085: // no usages, not test-covered
086: this .annotationStrategy = strategyFor(annotation);
087: this .typeLiteral = (TypeLiteral<T>) TypeLiteral
088: .fromSuperclassTypeParameter(getClass());
089: this .hashCode = computeHashCode();
090: }
091:
092: /**
093: * Constructs a new key. Derives the type from this class's type parameter.
094: *
095: * <p>Clients create an empty anonymous subclass. Doing so embeds the type
096: * parameter in the anonymous class's type hierarchy so we can reconstitute it
097: * at runtime despite erasure.
098: *
099: * <p>Example usage for a binding of type {@code Foo}:
100: *
101: * <p>{@code new Key<Foo>() {}}.
102: */
103: @SuppressWarnings("unchecked")
104: protected Key() {
105: this .annotationStrategy = NULL_STRATEGY;
106: this .typeLiteral = (TypeLiteral<T>) TypeLiteral
107: .fromSuperclassTypeParameter(getClass());
108: this .hashCode = computeHashCode();
109: }
110:
111: /**
112: * Unsafe. Constructs a key from a manually specified type.
113: */
114: @SuppressWarnings("unchecked")
115: private Key(Type type, AnnotationStrategy annotationStrategy) {
116: this .annotationStrategy = annotationStrategy;
117: this .typeLiteral = (TypeLiteral<T>) TypeLiteral.get(type);
118: this .hashCode = computeHashCode();
119: }
120:
121: /** Constructs a key from a manually specified type. */
122: private Key(TypeLiteral<T> typeLiteral,
123: AnnotationStrategy annotationStrategy) {
124: this .annotationStrategy = annotationStrategy;
125: this .typeLiteral = typeLiteral;
126: this .hashCode = computeHashCode();
127: }
128:
129: private int computeHashCode() {
130: return typeLiteral.hashCode() * 31
131: + annotationStrategy.hashCode();
132: }
133:
134: /**
135: * Gets the key type.
136: */
137: public TypeLiteral<T> getTypeLiteral() {
138: return typeLiteral;
139: }
140:
141: /**
142: * Gets the annotation type.
143: */
144: public Class<? extends Annotation> getAnnotationType() {
145: return annotationStrategy.getAnnotationType();
146: }
147:
148: /**
149: * Gets the annotation.
150: */
151: public Annotation getAnnotation() {
152: return annotationStrategy.getAnnotation();
153: }
154:
155: boolean hasAnnotationType() {
156: return annotationStrategy.getAnnotationType() != null;
157: }
158:
159: String getAnnotationName() {
160: Annotation annotation = annotationStrategy.getAnnotation();
161: if (annotation != null) {
162: return annotation.toString();
163: }
164:
165: // not test-covered
166: return annotationStrategy.getAnnotationType().toString();
167: }
168:
169: public int hashCode() {
170: return this .hashCode;
171: }
172:
173: Class<? super T> getRawType() {
174: return typeLiteral.getRawType();
175: }
176:
177: public boolean equals(Object o) {
178: if (o == this ) {
179: return true;
180: }
181: if (!(o instanceof Key<?>)) {
182: return false;
183: }
184: Key<?> other = (Key<?>) o;
185: return annotationStrategy.equals(other.annotationStrategy)
186: && typeLiteral.equals(other.typeLiteral);
187: }
188:
189: public String toString() {
190: return new ToStringBuilder(Key.class).add("type", typeLiteral)
191: .add("annotation", annotationStrategy).toString();
192: }
193:
194: /**
195: * Gets a key for an injection type and an annotation strategy.
196: */
197: static <T> Key<T> get(Class<T> type,
198: AnnotationStrategy annotationStrategy) {
199: return new SimpleKey<T>(type, annotationStrategy);
200: }
201:
202: /**
203: * Gets a key for an injection type.
204: */
205: public static <T> Key<T> get(Class<T> type) {
206: return new SimpleKey<T>(type, NULL_STRATEGY);
207: }
208:
209: /**
210: * Gets a key for an injection type and an annotation type.
211: */
212: public static <T> Key<T> get(Class<T> type,
213: Class<? extends Annotation> annotationType) {
214: return new SimpleKey<T>(type, strategyFor(annotationType));
215: }
216:
217: /**
218: * Gets a key for an injection type and an annotation.
219: */
220: public static <T> Key<T> get(Class<T> type, Annotation annotation) {
221: return new SimpleKey<T>(type, strategyFor(annotation));
222: }
223:
224: /**
225: * Gets a key for an injection type.
226: */
227: public static Key<?> get(Type type) {
228: return new SimpleKey<Object>(type, NULL_STRATEGY);
229: }
230:
231: /**
232: * Gets a key for an injection type and an annotation type.
233: */
234: public static Key<?> get(Type type,
235: Class<? extends Annotation> annotationType) {
236: return new SimpleKey<Object>(type, strategyFor(annotationType));
237: }
238:
239: /**
240: * Gets a key for an injection type and an annotation.
241: */
242: public static Key<?> get(Type type, Annotation annotation) {
243: return new SimpleKey<Object>(type, strategyFor(annotation));
244: }
245:
246: /**
247: * Gets a key for an injection type.
248: */
249: public static <T> Key<T> get(TypeLiteral<T> typeLiteral) {
250: return new SimpleKey<T>(typeLiteral, NULL_STRATEGY);
251: }
252:
253: /**
254: * Gets a key for an injection type and an annotation type.
255: */
256: public static <T> Key<T> get(TypeLiteral<T> typeLiteral,
257: Class<? extends Annotation> annotationType) {
258: return new SimpleKey<T>(typeLiteral,
259: strategyFor(annotationType));
260: }
261:
262: /**
263: * Gets a key for an injection type and an annotation.
264: */
265: public static <T> Key<T> get(TypeLiteral<T> typeLiteral,
266: Annotation annotation) {
267: return new SimpleKey<T>(typeLiteral, strategyFor(annotation));
268: }
269:
270: /**
271: * Gets a key for the given type, member and annotations.
272: */
273: static Key<?> get(Type type, Member member,
274: Annotation[] annotations, ErrorHandler errorHandler) {
275: Annotation found = null;
276: for (Annotation annotation : annotations) {
277: if (annotation.annotationType().getAnnotation(
278: BindingAnnotation.class) != null) {
279: if (found == null) {
280: found = annotation;
281: } else {
282: errorHandler.handle(StackTraceElements
283: .forMember(member),
284: ErrorMessages.DUPLICATE_ANNOTATIONS, found,
285: annotation);
286: }
287: }
288: }
289: Key<?> key = found == null ? Key.get(type) : Key.get(type,
290: found);
291: return key;
292: }
293:
294: /**
295: * Returns a new key of the specified type with the same annotation as this
296: * key.
297: */
298: <T> Key<T> ofType(Class<T> type) {
299: return new SimpleKey<T>(type, annotationStrategy);
300: }
301:
302: /**
303: * Returns a new key of the specified type with the same annotation as this
304: * key.
305: */
306: Key<?> ofType(Type type) {
307: return new SimpleKey<Object>(type, annotationStrategy);
308: }
309:
310: /**
311: * Returns true if this key has annotation attributes.
312: * @return
313: */
314: boolean hasAttributes() {
315: return annotationStrategy.hasAttributes();
316: }
317:
318: /**
319: * Returns this key without annotation attributes, i.e. with only the
320: * annotation type.
321: */
322: Key<T> withoutAttributes() {
323: return new SimpleKey<T>(typeLiteral, annotationStrategy
324: .withoutAttributes());
325: }
326:
327: private static class SimpleKey<T> extends Key<T> {
328:
329: private SimpleKey(Type type,
330: AnnotationStrategy annotationStrategy) {
331: super (type, annotationStrategy);
332: }
333:
334: private SimpleKey(TypeLiteral<T> typeLiteral,
335: AnnotationStrategy annotationStrategy) {
336: super (typeLiteral, annotationStrategy);
337: }
338: }
339:
340: interface AnnotationStrategy {
341:
342: Annotation getAnnotation();
343:
344: Class<? extends Annotation> getAnnotationType();
345:
346: boolean hasAttributes();
347:
348: AnnotationStrategy withoutAttributes();
349: }
350:
351: static final AnnotationStrategy NULL_STRATEGY = new AnnotationStrategy() {
352:
353: public boolean hasAttributes() {
354: return false;
355: }
356:
357: public AnnotationStrategy withoutAttributes() {
358: throw new UnsupportedOperationException(
359: "Key already has no attributes.");
360: }
361:
362: public Annotation getAnnotation() {
363: return null;
364: }
365:
366: public Class<? extends Annotation> getAnnotationType() {
367: return null;
368: }
369:
370: public boolean equals(Object o) {
371: return o == NULL_STRATEGY;
372: }
373:
374: public int hashCode() {
375: return 0;
376: }
377:
378: public String toString() {
379: return "[none]";
380: }
381: };
382:
383: /**
384: * Returns {@code true} if the given annotation type has no attributes.
385: */
386: static boolean isMarker(Class<? extends Annotation> annotationType) {
387: return annotationType.getDeclaredMethods().length == 0;
388: }
389:
390: /**
391: * Gets the strategy for an annotation.
392: */
393: static AnnotationStrategy strategyFor(Annotation annotation) {
394: nonNull(annotation, "annotation");
395: Class<? extends Annotation> annotationType = annotation
396: .annotationType();
397: ensureRetainedAtRuntime(annotationType);
398: ensureIsBindingAnnotation(annotationType);
399: return new AnnotationInstanceStrategy(annotation);
400: }
401:
402: /**
403: * Gets the strategy for an annotation type.
404: */
405: static AnnotationStrategy strategyFor(
406: Class<? extends Annotation> annotationType) {
407: nonNull(annotationType, "annotation type");
408: ensureRetainedAtRuntime(annotationType);
409: ensureIsBindingAnnotation(annotationType);
410: return new AnnotationTypeStrategy(annotationType, null);
411: }
412:
413: private static void ensureRetainedAtRuntime(
414: Class<? extends Annotation> annotationType) {
415: if (!Annotations.isRetainedAtRuntime(annotationType)) {
416: throw new IllegalArgumentException(annotationType.getName()
417: + " is not retained at runtime."
418: + " Please annotate it with @Retention(RUNTIME).");
419: }
420: }
421:
422: private static void ensureIsBindingAnnotation(
423: Class<? extends Annotation> annotationType) {
424: if (!isBindingAnnotation(annotationType)) {
425: throw new IllegalArgumentException(annotationType.getName()
426: + " is not a binding annotation."
427: + " Please annotate it with @BindingAnnotation.");
428: }
429: }
430:
431: // this class not test-covered
432: static class AnnotationInstanceStrategy implements
433: AnnotationStrategy {
434:
435: final Annotation annotation;
436:
437: AnnotationInstanceStrategy(Annotation annotation) {
438: this .annotation = nonNull(annotation, "annotation");
439: }
440:
441: public boolean hasAttributes() {
442: return true;
443: }
444:
445: public AnnotationStrategy withoutAttributes() {
446: return new AnnotationTypeStrategy(getAnnotationType(),
447: annotation);
448: }
449:
450: public Annotation getAnnotation() {
451: return annotation;
452: }
453:
454: public Class<? extends Annotation> getAnnotationType() {
455: return annotation.annotationType();
456: }
457:
458: public boolean equals(Object o) {
459: if (!(o instanceof AnnotationInstanceStrategy)) {
460: return false;
461: }
462:
463: AnnotationInstanceStrategy other = (AnnotationInstanceStrategy) o;
464: return annotation.equals(other.annotation);
465: }
466:
467: public int hashCode() {
468: return annotation.hashCode();
469: }
470:
471: public String toString() {
472: return annotation.toString();
473: }
474: }
475:
476: static class AnnotationTypeStrategy implements AnnotationStrategy {
477:
478: final Class<? extends Annotation> annotationType;
479:
480: // Keep the instance around if we have it so the client can request it.
481: final Annotation annotation;
482:
483: AnnotationTypeStrategy(
484: Class<? extends Annotation> annotationType,
485: Annotation annotation) {
486: this .annotationType = nonNull(annotationType,
487: "annotation type");
488: this .annotation = annotation;
489: }
490:
491: public boolean hasAttributes() {
492: return false;
493: }
494:
495: public AnnotationStrategy withoutAttributes() {
496: throw new UnsupportedOperationException(
497: "Key already has no attributes.");
498: }
499:
500: public Annotation getAnnotation() {
501: return annotation;
502: }
503:
504: public Class<? extends Annotation> getAnnotationType() {
505: return annotationType;
506: }
507:
508: public boolean equals(Object o) {
509: if (!(o instanceof AnnotationTypeStrategy)) {
510: return false;
511: }
512:
513: AnnotationTypeStrategy other = (AnnotationTypeStrategy) o;
514: return annotationType.equals(other.annotationType);
515: }
516:
517: public int hashCode() {
518: return annotationType.hashCode();
519: }
520:
521: public String toString() {
522: return "@" + annotationType.getName();
523: }
524: }
525:
526: static boolean isBindingAnnotation(Annotation annotation) {
527: return isBindingAnnotation(annotation.annotationType());
528: }
529:
530: static boolean isBindingAnnotation(
531: Class<? extends Annotation> annotationType) {
532: return annotationType
533: .isAnnotationPresent(BindingAnnotation.class);
534: }
535: }
|