📄 key.java
字号:
/** * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.google.inject;import static com.google.inject.util.Objects.nonNull;import com.google.inject.util.StackTraceElements;import com.google.inject.util.ToStringBuilder;import com.google.inject.util.Annotations;import java.lang.annotation.Annotation;import java.lang.reflect.Member;import java.lang.reflect.Type;/** * Binding key consisting of an injection type and an optional annotation. * Matches the type and annotation at a point of injection. * * <p>For example, {@code Key.get(Service.class, Transactional.class)} will * match: * * <pre> * {@literal @}Inject * public void setService({@literal @}Transactional Service service) { * ... * } * </pre> * * <p>{@code Key} supports generic types via subclassing just like {@link * TypeLiteral}. * * @author crazybob@google.com (Bob Lee) */public abstract class Key<T> { final AnnotationStrategy annotationStrategy; final TypeLiteral<T> typeLiteral; final int hashCode; /** * Constructs a new key. Derives the type from this class's type parameter. * * <p>Clients create an empty anonymous subclass. Doing so embeds the type * parameter in the anonymous class's type hierarchy so we can reconstitute it * at runtime despite erasure. * * <p>Example usage for a binding of type {@code Foo} annotated with * {@code @Bar}: * * <p>{@code new Key<Foo>(Bar.class) {}}. */ @SuppressWarnings("unchecked") protected Key(Class<? extends Annotation> annotationType) { this.annotationStrategy = strategyFor(annotationType); this.typeLiteral = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()); this.hashCode = computeHashCode(); } /** * Constructs a new key. Derives the type from this class's type parameter. * * <p>Clients create an empty anonymous subclass. Doing so embeds the type * parameter in the anonymous class's type hierarchy so we can reconstitute it * at runtime despite erasure. * * <p>Example usage for a binding of type {@code Foo} annotated with * {@code @Bar}: * * <p>{@code new Key<Foo>(new Bar()) {}}. */ @SuppressWarnings("unchecked") protected Key(Annotation annotation) { // no usages, not test-covered this.annotationStrategy = strategyFor(annotation); this.typeLiteral = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()); this.hashCode = computeHashCode(); } /** * Constructs a new key. Derives the type from this class's type parameter. * * <p>Clients create an empty anonymous subclass. Doing so embeds the type * parameter in the anonymous class's type hierarchy so we can reconstitute it * at runtime despite erasure. * * <p>Example usage for a binding of type {@code Foo}: * * <p>{@code new Key<Foo>() {}}. */ @SuppressWarnings("unchecked") protected Key() { this.annotationStrategy = NULL_STRATEGY; this.typeLiteral = (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()); this.hashCode = computeHashCode(); } /** * Unsafe. Constructs a key from a manually specified type. */ @SuppressWarnings("unchecked") private Key(Type type, AnnotationStrategy annotationStrategy) { this.annotationStrategy = annotationStrategy; this.typeLiteral = (TypeLiteral<T>) TypeLiteral.get(type); this.hashCode = computeHashCode(); } /** Constructs a key from a manually specified type. */ private Key(TypeLiteral<T> typeLiteral, AnnotationStrategy annotationStrategy) { this.annotationStrategy = annotationStrategy; this.typeLiteral = typeLiteral; this.hashCode = computeHashCode(); } private int computeHashCode() { return typeLiteral.hashCode() * 31 + annotationStrategy.hashCode(); } /** * Gets the key type. */ public TypeLiteral<T> getTypeLiteral() { return typeLiteral; } /** * Gets the annotation type. */ public Class<? extends Annotation> getAnnotationType() { return annotationStrategy.getAnnotationType(); } /** * Gets the annotation. */ public Annotation getAnnotation() { return annotationStrategy.getAnnotation(); } boolean hasAnnotationType() { return annotationStrategy.getAnnotationType() != null; } String getAnnotationName() { Annotation annotation = annotationStrategy.getAnnotation(); if (annotation != null) { return annotation.toString(); } // not test-covered return annotationStrategy.getAnnotationType().toString(); } public int hashCode() { return this.hashCode; } Class<? super T> getRawType() { return typeLiteral.getRawType(); } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof Key<?>)) { return false; } Key<?> other = (Key<?>) o; return annotationStrategy.equals(other.annotationStrategy) && typeLiteral.equals(other.typeLiteral); } public String toString() { return new ToStringBuilder(Key.class) .add("type", typeLiteral) .add("annotation", annotationStrategy) .toString(); } /** * Gets a key for an injection type and an annotation strategy. */ static <T> Key<T> get(Class<T> type, AnnotationStrategy annotationStrategy) { return new SimpleKey<T>(type, annotationStrategy); } /** * Gets a key for an injection type. */ public static <T> Key<T> get(Class<T> type) { return new SimpleKey<T>(type, NULL_STRATEGY); } /** * Gets a key for an injection type and an annotation type. */ public static <T> Key<T> get(Class<T> type, Class<? extends Annotation> annotationType) { return new SimpleKey<T>(type, strategyFor(annotationType)); } /** * Gets a key for an injection type and an annotation. */ public static <T> Key<T> get(Class<T> type, Annotation annotation) { return new SimpleKey<T>(type, strategyFor(annotation)); } /** * Gets a key for an injection type. */ public static Key<?> get(Type type) { return new SimpleKey<Object>(type, NULL_STRATEGY); } /** * Gets a key for an injection type and an annotation type. */ public static Key<?> get(Type type, Class<? extends Annotation> annotationType) { return new SimpleKey<Object>(type, strategyFor(annotationType)); } /** * Gets a key for an injection type and an annotation. */ public static Key<?> get(Type type, Annotation annotation) { return new SimpleKey<Object>(type, strategyFor(annotation)); } /** * Gets a key for an injection type. */ public static <T> Key<T> get(TypeLiteral<T> typeLiteral) { return new SimpleKey<T>(typeLiteral, NULL_STRATEGY); } /** * Gets a key for an injection type and an annotation type. */ public static <T> Key<T> get(TypeLiteral<T> typeLiteral, Class<? extends Annotation> annotationType) { return new SimpleKey<T>(typeLiteral, strategyFor(annotationType)); } /** * Gets a key for an injection type and an annotation. */ public static <T> Key<T> get(TypeLiteral<T> typeLiteral, Annotation annotation) { return new SimpleKey<T>(typeLiteral, strategyFor(annotation)); } /** * Gets a key for the given type, member and annotations. */ static Key<?> get(Type type, Member member, Annotation[] annotations, ErrorHandler errorHandler) { Annotation found = null; for (Annotation annotation : annotations) { if (annotation.annotationType().getAnnotation(BindingAnnotation.class) != null) { if (found == null) { found = annotation; } else { errorHandler.handle(StackTraceElements.forMember(member), ErrorMessages.DUPLICATE_ANNOTATIONS, found, annotation); } } } Key<?> key = found == null ? Key.get(type) : Key.get(type, found); return key; } /** * Returns a new key of the specified type with the same annotation as this * key. */ <T> Key<T> ofType(Class<T> type) { return new SimpleKey<T>(type, annotationStrategy); } /** * Returns a new key of the specified type with the same annotation as this * key. */ Key<?> ofType(Type type) { return new SimpleKey<Object>(type, annotationStrategy); } /** * Returns true if this key has annotation attributes. * @return */ boolean hasAttributes() { return annotationStrategy.hasAttributes(); } /** * Returns this key without annotation attributes, i.e. with only the * annotation type. */ Key<T> withoutAttributes() { return new SimpleKey<T>(typeLiteral, annotationStrategy.withoutAttributes()); } private static class SimpleKey<T> extends Key<T> { private SimpleKey(Type type, AnnotationStrategy annotationStrategy) { super(type, annotationStrategy); } private SimpleKey(TypeLiteral<T> typeLiteral, AnnotationStrategy annotationStrategy) { super(typeLiteral, annotationStrategy); } } interface AnnotationStrategy { Annotation getAnnotation(); Class<? extends Annotation> getAnnotationType(); boolean hasAttributes(); AnnotationStrategy withoutAttributes(); } static final AnnotationStrategy NULL_STRATEGY = new AnnotationStrategy() { public boolean hasAttributes() { return false; } public AnnotationStrategy withoutAttributes() { throw new UnsupportedOperationException("Key already has no attributes."); } public Annotation getAnnotation() { return null; } public Class<? extends Annotation> getAnnotationType() { return null; } public boolean equals(Object o) { return o == NULL_STRATEGY; } public int hashCode() { return 0; } public String toString() { return "[none]"; } }; /** * Returns {@code true} if the given annotation type has no attributes. */ static boolean isMarker(Class<? extends Annotation> annotationType) { return annotationType.getDeclaredMethods().length == 0; } /** * Gets the strategy for an annotation. */ static AnnotationStrategy strategyFor(Annotation annotation) { nonNull(annotation, "annotation"); Class<? extends Annotation> annotationType = annotation.annotationType(); ensureRetainedAtRuntime(annotationType); ensureIsBindingAnnotation(annotationType); return new AnnotationInstanceStrategy(annotation); } /** * Gets the strategy for an annotation type. */ static AnnotationStrategy strategyFor( Class<? extends Annotation> annotationType) { nonNull(annotationType, "annotation type"); ensureRetainedAtRuntime(annotationType); ensureIsBindingAnnotation(annotationType); return new AnnotationTypeStrategy(annotationType, null); } private static void ensureRetainedAtRuntime( Class<? extends Annotation> annotationType) { if (!Annotations.isRetainedAtRuntime(annotationType)) { throw new IllegalArgumentException(annotationType.getName() + " is not retained at runtime." + " Please annotate it with @Retention(RUNTIME)."); } } private static void ensureIsBindingAnnotation( Class<? extends Annotation> annotationType) { if (!isBindingAnnotation(annotationType)) { throw new IllegalArgumentException(annotationType.getName() + " is not a binding annotation." + " Please annotate it with @BindingAnnotation."); } } // this class not test-covered static class AnnotationInstanceStrategy implements AnnotationStrategy { final Annotation annotation; AnnotationInstanceStrategy(Annotation annotation) { this.annotation = nonNull(annotation, "annotation"); } public boolean hasAttributes() { return true; } public AnnotationStrategy withoutAttributes() { return new AnnotationTypeStrategy(getAnnotationType(), annotation); } public Annotation getAnnotation() { return annotation; } public Class<? extends Annotation> getAnnotationType() { return annotation.annotationType(); } public boolean equals(Object o) { if (!(o instanceof AnnotationInstanceStrategy)) { return false; } AnnotationInstanceStrategy other = (AnnotationInstanceStrategy) o; return annotation.equals(other.annotation); } public int hashCode() { return annotation.hashCode(); } public String toString() { return annotation.toString(); } } static class AnnotationTypeStrategy implements AnnotationStrategy { final Class<? extends Annotation> annotationType; // Keep the instance around if we have it so the client can request it. final Annotation annotation; AnnotationTypeStrategy(Class<? extends Annotation> annotationType, Annotation annotation) { this.annotationType = nonNull(annotationType, "annotation type"); this.annotation = annotation; } public boolean hasAttributes() { return false; } public AnnotationStrategy withoutAttributes() { throw new UnsupportedOperationException("Key already has no attributes."); } public Annotation getAnnotation() { return annotation; } public Class<? extends Annotation> getAnnotationType() { return annotationType; } public boolean equals(Object o) { if (!(o instanceof AnnotationTypeStrategy)) { return false; } AnnotationTypeStrategy other = (AnnotationTypeStrategy) o; return annotationType.equals(other.annotationType); } public int hashCode() { return annotationType.hashCode(); } public String toString() { return "@" + annotationType.getName(); } } static boolean isBindingAnnotation(Annotation annotation) { return isBindingAnnotation(annotation.annotationType()); } static boolean isBindingAnnotation( Class<? extends Annotation> annotationType) { return annotationType.isAnnotationPresent(BindingAnnotation.class); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -