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

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

package com.google.inject.internal;

import com.google.common.collect.ImmutableSet;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.ProviderWithExtensionVisitor;

/**
 * A {@link ProviderInstanceBindingImpl} for implementing 'native' guice extensions.
 *
 * 

Beyond the normal binding contract that is mostly handled by our baseclass, this also * implements {@link DelayedInitialize} in order to initialize factory state. */ final class InternalProviderInstanceBindingImpl extends ProviderInstanceBindingImpl implements DelayedInitialize { enum InitializationTiming { /** This factory can be initialized eagerly. This should be the case for most things. */ EAGER, /** * Initialization of this factory should be delayed until after all other static initialization * completes. This will be useful for factories that need to call {@link * InjectorImpl#getExistingBinding(Key)} to not create jit bindings, but also want to be able to * conditionally consume jit bindings created by other other bindings. */ DELAYED } private final Factory originalFactory; InternalProviderInstanceBindingImpl( InjectorImpl injector, Key key, Object source, Factory originalFactory, InternalFactory scopedFactory, Scoping scoping) { super( injector, key, source, scopedFactory, scoping, originalFactory, ImmutableSet.of()); this.originalFactory = originalFactory; } InitializationTiming getInitializationTiming() { return originalFactory.initializationTiming; } @Override public void initialize(final InjectorImpl injector, final Errors errors) throws ErrorsException { originalFactory.source = getSource(); originalFactory.provisionCallback = injector.provisionListenerStore.get(this); // For these kinds of providers, the 'user supplied provider' is really 'guice supplied' // So make our user supplied provider just delegate to the guice supplied one. originalFactory.delegateProvider = getProvider(); originalFactory.initialize(injector, errors); } /** * A base factory implementation. Any Factories that delegate to other bindings should use the * {@code CyclicFactory} subclass, but trivial factories can use this one. */ abstract static class Factory implements InternalFactory, Provider, HasDependencies { private final InitializationTiming initializationTiming; private Object source; private Provider delegateProvider; ProvisionListenerStackCallback provisionCallback; Factory(InitializationTiming initializationTiming) { this.initializationTiming = initializationTiming; } /** * The binding source. * *

May be useful for augmenting runtime error messages. * *

Note: this will return {#code null} until {@link #initialize(InjectorImpl, Errors)} has * already been called. */ final Object getSource() { return source; } /** * A callback that allows for implementations to fetch dependencies on other bindings. * *

Will be called exactly once, prior to any call to {@link #doProvision}. */ abstract void initialize(InjectorImpl injector, Errors errors) throws ErrorsException; @Override public final T get() { Provider local = delegateProvider; if (local == null) { throw new IllegalStateException( "This Provider cannot be used until the Injector has been created."); } return local.get(); } @Override public T get(final InternalContext context, final Dependency dependency, boolean linked) throws InternalProvisionException { if (provisionCallback == null) { return doProvision(context, dependency); } else { return provisionCallback.provision(context, () -> doProvision(context, dependency)); } } /** * Creates an object to be injected. * * @throws com.google.inject.internal.InternalProvisionException if a value cannot be provided * @return instance to be injected */ protected abstract T doProvision(InternalContext context, Dependency dependency) throws InternalProvisionException; } /** * An base factory implementation that can be extended to provide a specialized implementation of * a {@link ProviderWithExtensionVisitor} and also implements {@link InternalFactory} */ abstract static class CyclicFactory extends Factory { CyclicFactory(InitializationTiming initializationTiming) { super(initializationTiming); } @Override public final T get( final InternalContext context, final Dependency dependency, boolean linked) throws InternalProvisionException { final ConstructionContext constructionContext = context.getConstructionContext(this); // We have a circular reference between bindings. Return a proxy. if (constructionContext.isConstructing()) { Class expectedType = dependency.getKey().getTypeLiteral().getRawType(); @SuppressWarnings("unchecked") T proxyType = (T) constructionContext.createProxy(context.getInjectorOptions(), expectedType); return proxyType; } // Optimization: Don't go through the callback stack if no one's listening. constructionContext.startConstruction(); try { if (provisionCallback == null) { return provision(dependency, context, constructionContext); } else { return provisionCallback.provision(context, () -> provision(dependency, context, constructionContext)); } } finally { constructionContext.removeCurrentReference(); constructionContext.finishConstruction(); } } private T provision( Dependency dependency, InternalContext context, ConstructionContext constructionContext) throws InternalProvisionException { try { T t = doProvision(context, dependency); constructionContext.setProxyDelegates(t); return t; } catch (InternalProvisionException ipe) { throw ipe.addSource(getSource()); } catch (Throwable t) { throw InternalProvisionException.errorInProvider(t).addSource(getSource()); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy