dagger.internal.codegen.Scope.java Source code

Java tutorial

Introduction

Here is the source code for dagger.internal.codegen.Scope.java

Source

/*
 * Copyright (C) 2015 The Dagger Authors.
 *
 * 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 static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.common.base.Preconditions.checkArgument;
import static dagger.internal.codegen.ErrorMessages.stripCommonTypePrefixes;
import static dagger.internal.codegen.InjectionAnnotations.getScopes;

import com.google.auto.common.AnnotationMirrors;
import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.auto.value.AutoValue;
import com.google.common.base.Equivalence;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import dagger.Reusable;
import dagger.producers.ProductionScope;
import dagger.releasablereferences.CanReleaseReferences;
import java.lang.annotation.Annotation;
import java.util.Optional;
import javax.inject.Singleton;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;

/** A javax.inject.Scope. */
@AutoValue
abstract class Scope {

    /** The underlying {@link AnnotationMirror} that represents the scope annotation. */
    abstract Equivalence.Wrapper<AnnotationMirror> scopeAnnotation();

    /**
     * Creates a {@link Scope} object from the {@link javax.inject.Scope}-annotated annotation type.
     */
    static Scope scope(AnnotationMirror scopeAnnotation) {
        checkArgument(isScope(scopeAnnotation));
        return new AutoValue_Scope(AnnotationMirrors.equivalence().wrap(scopeAnnotation));
    }

    /** Returns {@code true} if {@code scopeAnnotation} is a {@link javax.inject.Scope} annotation. */
    static boolean isScope(AnnotationMirror scopeAnnotation) {
        return isScope(MoreElements.asType(scopeAnnotation.getAnnotationType().asElement()));
    }

    /**
     * Returns {@code true} if {@code scopeAnnotationType} is a {@link javax.inject.Scope} annotation.
     */
    static boolean isScope(TypeElement scopeAnnotationType) {
        return isAnnotationPresent(scopeAnnotationType, javax.inject.Scope.class);
    }

    /**
     * Creates a {@link Scope} object from the {@link javax.inject.Scope}-annotated annotation type.
     */
    static Scope scope(TypeElement scopeType) {
        return scope(SimpleAnnotationMirror.of(scopeType));
    }

    private static Scope scope(Elements elements, Class<? extends Annotation> scopeAnnotationClass) {
        return scope(elements.getTypeElement(scopeAnnotationClass.getCanonicalName()));
    }

    /** Returns all of the associated scopes for a source code element. */
    static ImmutableSet<Scope> scopesOf(Element element) {
        return FluentIterable.from(getScopes(element)).transform(Scope::scope).toSet();
    }

    /**
     * Returns at most one associated scoped annotation from the source code element, throwing an
     * exception if there are more than one.
     */
    static Optional<Scope> uniqueScopeOf(Element element) {
        ImmutableSet<? extends AnnotationMirror> scopeAnnotations = getScopes(element);
        if (scopeAnnotations.isEmpty()) {
            return Optional.empty();
        }
        return Optional.of(scope(Iterables.getOnlyElement(scopeAnnotations)));
    }

    /**
     * Returns a representation for {@link ProductionScope @ProductionScope} scope.
     */
    static Scope productionScope(Elements elements) {
        return scope(elements, ProductionScope.class);
    }

    /**
     * Returns a representation for {@link Singleton @Singleton} scope.
     */
    static Scope singletonScope(Elements elements) {
        return scope(elements, Singleton.class);
    }

    /**
     * Returns a representation for {@link Reusable @Reusable} scope.
     */
    static Scope reusableScope(Elements elements) {
        return scope(elements, Reusable.class);
    }

    /**
     * Returns {@code true} for scopes that are annotated with {@link CanReleaseReferences} or some
     * other annotation that is itself annotated with {@link CanReleaseReferences}.
     */
    boolean canReleaseReferences() {
        return isAnnotationPresent(scopeAnnotationElement(), CanReleaseReferences.class)
                || !releasableReferencesMetadata().isEmpty();
    }

    /**
     * Returns the set of annotations on the scope that are themselves annotated with {@link
     * CanReleaseReferences}. These annotations are used as metadata for {@link
     * dagger.releasablereferences.TypedReleasableReferenceManager}.
     */
    ImmutableSet<? extends AnnotationMirror> releasableReferencesMetadata() {
        return getAnnotatedAnnotations(scopeAnnotationElement(), CanReleaseReferences.class);
    }

    /**
     * Returns the {@linkplain #releasableReferencesMetadata() releasable references metadata}
     * annotation of the given type, if there is one for this scope.
     */
    Optional<AnnotationMirror> releasableReferencesMetadata(TypeMirror metadataType) {
        for (AnnotationMirror metadata : releasableReferencesMetadata()) {
            if (MoreTypes.equivalence().equivalent(metadata.getAnnotationType(), metadataType)) {
                return Optional.of(metadata);
            }
        }
        return Optional.empty();
    }

    /**
     * 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>Does not return any annotation values, since {@link javax.inject.Scope @Scope}
     * annotations are not supposed to have any.
     */
    public String getReadableSource() {
        return stripCommonTypePrefixes("@" + getQualifiedName());
    }

    /**
     * Returns the fully qualified name of the annotation type.
     */
    public String getQualifiedName() {
        return scopeAnnotationElement().getQualifiedName().toString();
    }

    /**
     * The scope annotation element.
     */
    public TypeElement scopeAnnotationElement() {
        return MoreTypes.asTypeElement(scopeAnnotation().get().getAnnotationType());
    }

    /**
     * Returns a debug representation of the scope.
     */
    @Override
    public String toString() {
        return scopeAnnotation().get().toString();
    }
}