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