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

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

package com.google.inject.internal;

import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.DefaultBindingTargetVisitor;

import java.util.Set;

/**
 * Guarantees that processing of Binding elements happens in a sane way.
 */
abstract class AbstractBindingProcessor extends AbstractProcessor {

    // It's unfortunate that we have to maintain a blacklist of specific
    // classes, but we can't easily block the whole package because of
    // all our unit tests.
    private static final Set> FORBIDDEN_TYPES = ImmutableSet.of(
            AbstractModule.class,
            Binder.class,
            Binding.class,
            Injector.class,
            Key.class,
            MembersInjector.class,
            Module.class,
            Provider.class,
            Scope.class,
            Stage.class,
            TypeLiteral.class);

    protected final ProcessedBindingData bindingData;

    AbstractBindingProcessor(Errors errors, ProcessedBindingData bindingData) {
        super(errors);
        this.bindingData = bindingData;
    }

    protected  UntargettedBindingImpl invalidBinding(
            InjectorImpl injector, Key key, Object source) {
        return new UntargettedBindingImpl(injector, key, source);
    }

    protected void putBinding(BindingImpl binding) {
        Key key = binding.getKey();

        Class rawType = key.getTypeLiteral().getRawType();
        if (FORBIDDEN_TYPES.contains(rawType)) {
            errors.cannotBindToGuiceType(rawType.getSimpleName());
            return;
        }

        BindingImpl original = injector.getExistingBinding(key);
        if (original != null) {
            // If it failed because of an explicit duplicate binding...
            if (injector.state.getExplicitBinding(key) != null) {
                try {
                    if (!isOkayDuplicate(original, binding, injector.state)) {
                        errors.bindingAlreadySet(key, original.getSource());
                        return;
                    }
                } catch (Throwable t) {
                    errors.errorCheckingDuplicateBinding(key, original.getSource(), t);
                    return;
                }
            } else {
                // Otherwise, it failed because of a duplicate JIT binding
                // in the parent
                errors.jitBindingAlreadySet(key);
                return;
            }
        }

        // prevent the parent from creating a JIT binding for this key
        injector.state.parent().blacklist(key, injector.state, binding.getSource());
        injector.state.putBinding(key, binding);
    }

    /**
     * We tolerate duplicate bindings if one exposes the other or if the two bindings
     * are considered duplicates.
     *
     * @param original the binding in the parent injector (candidate for an exposing binding)
     * @param binding  the binding to check (candidate for the exposed binding)
     */
    private boolean isOkayDuplicate(BindingImpl original, BindingImpl binding, State state) {
        if (original instanceof ExposedBindingImpl) {
            ExposedBindingImpl exposed = (ExposedBindingImpl) original;
            InjectorImpl exposedFrom = (InjectorImpl) exposed.getPrivateElements().getInjector();
            return (exposedFrom == binding.getInjector());
        } else {
            original = (BindingImpl) state.getExplicitBindingsThisLevel().get(binding.getKey());
            // If no original at this level, the original was on a parent, and we don't
            // allow deduplication between parents & children.
            return original != null && original.equals(binding);
        }
    }

    private  void validateKey(Object source, Key key) {
        Annotations.checkForMisplacedScopeAnnotations(
                key.getTypeLiteral().getRawType(), source, errors);
    }

    /**
     * Processor for visiting bindings.  Each overriden method that wants to
     * actually process the binding should call prepareBinding first.
     */
    abstract class Processor extends DefaultBindingTargetVisitor {
        final Object source;
        final Key key;
        final Class rawType;
        Scoping scoping;

        Processor(BindingImpl binding) {
            source = binding.getSource();
            key = binding.getKey();
            rawType = key.getTypeLiteral().getRawType();
            scoping = binding.getScoping();
        }

        protected void prepareBinding() {
            validateKey(source, key);
            scoping = Scoping.makeInjectable(scoping, injector, errors);
        }

        /**
         * Schedule initialization of this binding to occur immediately after all bindings have been
         * initialially processed.
         */
        protected void scheduleInitialization(BindingImpl binding) {
            bindingData.addUninitializedBinding(() -> initializeBinding(binding));
        }

        /**
         * Schedule initialization for this binding to occur after all other static initialization of
         * bindings.
         */
        protected void scheduleDelayedInitialization(BindingImpl binding) {
            bindingData.addDelayedUninitializedBinding(() -> initializeBinding(binding));
        }

        private void initializeBinding(BindingImpl binding) {
            try {
                binding.getInjector().initializeBinding(binding, errors.withSource(source));
            } catch (ErrorsException e) {
                errors.merge(e.getErrors());
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy