/* * Copyright (C) 2015 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 dagger.internal.codegen; import com.google.auto.common.AnnotationMirrors; import com.google.auto.common.MoreTypes; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import javax.annotation.Nullable; import javax.inject.Singleton; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import static com.google.auto.common.MoreTypes.isTypeOf; import static dagger.internal.codegen.ErrorMessages.stripCommonTypePrefixes; import static dagger.internal.codegen.InjectionAnnotations.getScopeAnnotation; /** * A representation of the scope (or lack of it) associated with a component, providing method * or injection location. */ final class Scope { /** * An internal representation for an unscoped binding. */ private static final Scope UNSCOPED = new Scope(); /** * The underlying {@link AnnotationMirror} that represents the scope annotation. */ @Nullable private final AnnotationMirror annotationMirror; private Scope(@Nullable AnnotationMirror annotationMirror) { this.annotationMirror = annotationMirror; } private Scope() { this(null); } /** * Returns representation for an unscoped binding. */ static Scope unscoped() { return UNSCOPED; } /** * If the source code element has an associated scoped annotation then returns a representation * of that scope, otherwise returns a representation for an unscoped binding. */ static Scope scopeOf(Element element) { Optional<AnnotationMirror> scopeAnnotation = getScopeAnnotation(element); return scopeAnnotation.isPresent() ? new Scope(scopeAnnotation.get()) : UNSCOPED; } /** * Returns true if the scope is present, i.e. it's not unscoped binding. */ public boolean isPresent() { return annotationMirror != null; } /** * Returns true if the scope represents the {@link Singleton @Singleton} annotation. */ public boolean isSingleton() { return annotationMirror != null && isTypeOf(Singleton.class, annotationMirror.getAnnotationType()); } /** * Returns the readable source representation (name with @ prefix) of the annotation type. * * <p>It's readable source because it has had common package prefixes removed, e.g. * {@code @javax.inject.Singleton} is returned as {@code @Singleton}. * * <p>Make sure that the scope is actually {@link #isPresent() present} before calling as it will * throw an {@link IllegalStateException} otherwise. This does not return any annotation values * as according to {@link javax.inject.Scope} scope annotations are not supposed to use them. */ public String getReadableSource() { return stripCommonTypePrefixes("@" + getQualifiedName()); } /** * Returns the fully qualified name of the annotation type. * * <p>Make sure that the scope is actually {@link #isPresent() present} before calling as it will * throw an {@link IllegalStateException} otherwise. This does not return any annotation values * as according to {@link javax.inject.Scope} scope annotations are not supposed to use them. */ public String getQualifiedName() { Preconditions.checkState(annotationMirror != null, "Cannot create a stripped source representation of no annotation"); TypeElement typeElement = MoreTypes.asTypeElement(annotationMirror.getAnnotationType()); return typeElement.getQualifiedName().toString(); } /** * Scopes are equal if the underlying {@link AnnotationMirror} are equivalent according to * {@link AnnotationMirrors#equivalence()}. */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (obj instanceof Scope) { Scope that = (Scope) obj; return AnnotationMirrors.equivalence() .equivalent(this.annotationMirror, that.annotationMirror); } else { return false; } } @Override public int hashCode() { return AnnotationMirrors.equivalence().hash(annotationMirror); } /** * Returns a debug representation of the scope. */ @Override public String toString() { return annotationMirror == null ? "UNSCOPED" : annotationMirror.toString(); } }