All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.inject.internal.Scoping Maven / Gradle / Ivy

package com.google.inject.internal;

import com.google.common.base.Objects;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.Scopes;
import com.google.inject.Singleton;
import com.google.inject.Stage;
import com.google.inject.binder.ScopedBindingBuilder;
import com.google.inject.spi.BindingScopingVisitor;
import com.google.inject.spi.ScopeBinding;

import java.lang.annotation.Annotation;

/**
 * References a scope, either directly (as a scope instance), or indirectly (as a scope annotation).
 * The scope's eager or laziness is also exposed.
 *
 */
public abstract class Scoping {

    /**
     * No scoping annotation has been applied. Note that this is different from {@code
     * in(Scopes.NO_SCOPE)}, where the 'NO_SCOPE' has been explicitly applied.
     */
    public static final Scoping UNSCOPED = new Scoping() {
        @Override
        public  V acceptVisitor(BindingScopingVisitor visitor) {
            return visitor.visitNoScoping();
        }

        @Override
        public Scope getScopeInstance() {
            return Scopes.NO_SCOPE;
        }

        @Override
        public String toString() {
            return Scopes.NO_SCOPE.toString();
        }

        @Override
        public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
            // do nothing
        }
    };

    public static final Scoping SINGLETON_ANNOTATION = new Scoping() {
        @Override
        public  V acceptVisitor(BindingScopingVisitor visitor) {
            return visitor.visitScopeAnnotation(Singleton.class);
        }

        @Override
        public Class getScopeAnnotation() {
            return Singleton.class;
        }

        @Override
        public String toString() {
            return Singleton.class.getName();
        }

        @Override
        public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
            scopedBindingBuilder.in(Singleton.class);
        }
    };

    public static final Scoping SINGLETON_INSTANCE = new Scoping() {
        @Override
        public  V acceptVisitor(BindingScopingVisitor visitor) {
            return visitor.visitScope(Scopes.SINGLETON);
        }

        @Override
        public Scope getScopeInstance() {
            return Scopes.SINGLETON;
        }

        @Override
        public String toString() {
            return Scopes.SINGLETON.toString();
        }

        @Override
        public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
            scopedBindingBuilder.in(Scopes.SINGLETON);
        }
    };

    public static final Scoping EAGER_SINGLETON = new Scoping() {
        @Override
        public  V acceptVisitor(BindingScopingVisitor visitor) {
            return visitor.visitEagerSingleton();
        }

        @Override
        public Scope getScopeInstance() {
            return Scopes.SINGLETON;
        }

        @Override
        public String toString() {
            return "eager singleton";
        }

        @Override
        public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
            scopedBindingBuilder.asEagerSingleton();
        }
    };

    private Scoping() {
    }

    public static Scoping forAnnotation(final Class scopingAnnotation) {
        if (scopingAnnotation == Singleton.class
                || scopingAnnotation == javax.inject.Singleton.class) {
            return SINGLETON_ANNOTATION;
        }

        return new Scoping() {
            @Override
            public  V acceptVisitor(BindingScopingVisitor visitor) {
                return visitor.visitScopeAnnotation(scopingAnnotation);
            }

            @Override
            public Class getScopeAnnotation() {
                return scopingAnnotation;
            }

            @Override
            public String toString() {
                return scopingAnnotation.getName();
            }

            @Override
            public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
                scopedBindingBuilder.in(scopingAnnotation);
            }
        };
    }

    public static Scoping forInstance(final Scope scope) {
        if (scope == Scopes.SINGLETON) {
            return SINGLETON_INSTANCE;
        }

        return new Scoping() {
            @Override
            public  V acceptVisitor(BindingScopingVisitor visitor) {
                return visitor.visitScope(scope);
            }

            @Override
            public Scope getScopeInstance() {
                return scope;
            }

            @Override
            public String toString() {
                return scope.toString();
            }

            @Override
            public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
                scopedBindingBuilder.in(scope);
            }
        };
    }

    /**
     * Scopes an internal factory.
     */
    static  InternalFactory scope(Key key, InjectorImpl injector,
                                                  InternalFactory creator, Object source, Scoping scoping) {

        if (scoping.isNoScope()) {
            return creator;
        }

        Scope scope = scoping.getScopeInstance();

        Provider scoped = scope.scope(key, new ProviderToInternalFactoryAdapter(injector, creator));
        return new InternalFactoryToProviderAdapter(scoped, source);
    }

    /**
     * Replaces annotation scopes with instance scopes using the Injector's annotation-to-instance
     * map. If the scope annotation has no corresponding instance, an error will be added and unscoped
     * will be retuned.
     */
    static Scoping makeInjectable(Scoping scoping, InjectorImpl injector, Errors errors) {
        Class scopeAnnotation = scoping.getScopeAnnotation();
        if (scopeAnnotation == null) {
            return scoping;
        }

        ScopeBinding scope = injector.state.getScopeBinding(scopeAnnotation);
        if (scope != null) {
            return forInstance(scope.getScope());
        }

        errors.scopeNotFound(scopeAnnotation);
        return UNSCOPED;
    }

    /**
     * Returns true if this scope was explicitly applied. If no scope was explicitly applied then the
     * scoping annotation will be used.
     */
    public boolean isExplicitlyScoped() {
        return this != UNSCOPED;
    }

    /**
     * Returns true if this is the default scope. In this case a new instance will be provided for
     * each injection.
     */
    public boolean isNoScope() {
        return getScopeInstance() == Scopes.NO_SCOPE;
    }

    /**
     * Returns true if this scope is a singleton that should be loaded eagerly in {@code stage}.
     */
    public boolean isEagerSingleton(Stage stage) {
        if (this == EAGER_SINGLETON) {
            return true;
        }

        return stage == Stage.PRODUCTION && (this == SINGLETON_ANNOTATION || this == SINGLETON_INSTANCE);

    }

    /**
     * Returns the scope instance, or {@code null} if that isn't known for this instance.
     */
    public Scope getScopeInstance() {
        return null;
    }

    /**
     * Returns the scope annotation, or {@code null} if that isn't known for this instance.
     */
    public Class getScopeAnnotation() {
        return null;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Scoping) {
            Scoping o = (Scoping) obj;
            return Objects.equal(getScopeAnnotation(), o.getScopeAnnotation())
                    && Objects.equal(getScopeInstance(), o.getScopeInstance());
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getScopeAnnotation(), getScopeInstance());
    }

    public abstract  V acceptVisitor(BindingScopingVisitor visitor);

    public abstract void applyTo(ScopedBindingBuilder scopedBindingBuilder);
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy