1 package com.google.inject.internal; 2 3 import com.google.common.collect.ImmutableSet; 4 import com.google.inject.Key; 5 import com.google.inject.Provider; 6 import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback; 7 import com.google.inject.spi.Dependency; 8 import com.google.inject.spi.HasDependencies; 9 import com.google.inject.spi.InjectionPoint; 10 import com.google.inject.spi.ProviderWithExtensionVisitor; 11 12 /** 13 * A {@link ProviderInstanceBindingImpl} for implementing 'native' guice extensions. 14 * 15 * <p>Beyond the normal binding contract that is mostly handled by our baseclass, this also 16 * implements {@link DelayedInitialize} in order to initialize factory state. 17 */ 18 final class InternalProviderInstanceBindingImpl<T> extends ProviderInstanceBindingImpl<T> 19 implements DelayedInitialize { 20 enum InitializationTiming { 21 /** This factory can be initialized eagerly. This should be the case for most things. */ 22 EAGER, 23 24 /** 25 * Initialization of this factory should be delayed until after all other static initialization 26 * completes. This will be useful for factories that need to call {@link 27 * InjectorImpl#getExistingBinding(Key)} to not create jit bindings, but also want to be able to 28 * conditionally consume jit bindings created by other other bindings. 29 */ 30 DELAYED; 31 } 32 33 private final Factory<T> originalFactory; 34 InternalProviderInstanceBindingImpl( InjectorImpl injector, Key<T> key, Object source, Factory<T> originalFactory, InternalFactory<? extends T> scopedFactory, Scoping scoping)35 InternalProviderInstanceBindingImpl( 36 InjectorImpl injector, 37 Key<T> key, 38 Object source, 39 Factory<T> originalFactory, 40 InternalFactory<? extends T> scopedFactory, 41 Scoping scoping) { 42 super( 43 injector, 44 key, 45 source, 46 scopedFactory, 47 scoping, 48 originalFactory, 49 ImmutableSet.<InjectionPoint>of()); 50 this.originalFactory = originalFactory; 51 } 52 getInitializationTiming()53 InitializationTiming getInitializationTiming() { 54 return originalFactory.initializationTiming; 55 } 56 57 @Override initialize(final InjectorImpl injector, final Errors errors)58 public void initialize(final InjectorImpl injector, final Errors errors) throws ErrorsException { 59 originalFactory.source = getSource(); 60 originalFactory.provisionCallback = injector.provisionListenerStore.get(this); 61 // For these kinds of providers, the 'user supplied provider' is really 'guice supplied' 62 // So make our user supplied provider just delegate to the guice supplied one. 63 originalFactory.delegateProvider = getProvider(); 64 originalFactory.initialize(injector, errors); 65 } 66 67 /** 68 * A base factory implementation. Any Factories that delegate to other bindings should use the 69 * {@code CyclicFactory} subclass, but trivial factories can use this one. 70 */ 71 abstract static class Factory<T> implements InternalFactory<T>, Provider<T>, HasDependencies { 72 private final InitializationTiming initializationTiming; 73 private Object source; 74 private Provider<T> delegateProvider; 75 ProvisionListenerStackCallback<T> provisionCallback; 76 Factory(InitializationTiming initializationTiming)77 Factory(InitializationTiming initializationTiming) { 78 this.initializationTiming = initializationTiming; 79 } 80 /** 81 * The binding source. 82 * 83 * <p>May be useful for augmenting runtime error messages. 84 * 85 * <p>Note: this will return {#code null} until {@link #initialize(InjectorImpl, Errors)} has 86 * already been called. 87 */ getSource()88 final Object getSource() { 89 return source; 90 } 91 92 /** 93 * A callback that allows for implementations to fetch dependencies on other bindings. 94 * 95 * <p>Will be called exactly once, prior to any call to {@link #doProvision}. 96 */ initialize(InjectorImpl injector, Errors errors)97 abstract void initialize(InjectorImpl injector, Errors errors) throws ErrorsException; 98 99 @Override get()100 public final T get() { 101 Provider<T> local = delegateProvider; 102 if (local == null) { 103 throw new IllegalStateException( 104 "This Provider cannot be used until the Injector has been created."); 105 } 106 return local.get(); 107 } 108 109 @Override get(final InternalContext context, final Dependency<?> dependency, boolean linked)110 public T get(final InternalContext context, final Dependency<?> dependency, boolean linked) 111 throws InternalProvisionException { 112 if (provisionCallback == null) { 113 return doProvision(context, dependency); 114 } else { 115 return provisionCallback.provision( 116 context, 117 new ProvisionCallback<T>() { 118 @Override 119 public T call() throws InternalProvisionException { 120 return doProvision(context, dependency); 121 } 122 }); 123 } 124 } 125 /** 126 * Creates an object to be injected. 127 * 128 * @throws com.google.inject.internal.InternalProvisionException if a value cannot be provided 129 * @return instance to be injected 130 */ doProvision(InternalContext context, Dependency<?> dependency)131 protected abstract T doProvision(InternalContext context, Dependency<?> dependency) 132 throws InternalProvisionException; 133 } 134 135 /** 136 * An base factory implementation that can be extended to provide a specialized implementation of 137 * a {@link ProviderWithExtensionVisitor} and also implements {@link InternalFactory} 138 */ 139 abstract static class CyclicFactory<T> extends Factory<T> { 140 141 CyclicFactory(InitializationTiming initializationTiming) { 142 super(initializationTiming); 143 } 144 145 @Override 146 public final T get( 147 final InternalContext context, final Dependency<?> dependency, boolean linked) 148 throws InternalProvisionException { 149 final ConstructionContext<T> constructionContext = context.getConstructionContext(this); 150 // We have a circular reference between bindings. Return a proxy. 151 if (constructionContext.isConstructing()) { 152 Class<?> expectedType = dependency.getKey().getTypeLiteral().getRawType(); 153 @SuppressWarnings("unchecked") 154 T proxyType = 155 (T) constructionContext.createProxy(context.getInjectorOptions(), expectedType); 156 return proxyType; 157 } 158 // Optimization: Don't go through the callback stack if no one's listening. 159 constructionContext.startConstruction(); 160 try { 161 if (provisionCallback == null) { 162 return provision(dependency, context, constructionContext); 163 } else { 164 return provisionCallback.provision( 165 context, 166 new ProvisionCallback<T>() { 167 @Override 168 public T call() throws InternalProvisionException { 169 return provision(dependency, context, constructionContext); 170 } 171 }); 172 } 173 } finally { 174 constructionContext.removeCurrentReference(); 175 constructionContext.finishConstruction(); 176 } 177 } 178 179 private T provision( 180 Dependency<?> dependency, 181 InternalContext context, 182 ConstructionContext<T> constructionContext) 183 throws InternalProvisionException { 184 try { 185 T t = doProvision(context, dependency); 186 constructionContext.setProxyDelegates(t); 187 return t; 188 } catch (InternalProvisionException ipe) { 189 throw ipe.addSource(getSource()); 190 } catch (Throwable t) { 191 throw InternalProvisionException.errorInProvider(t).addSource(getSource()); 192 } 193 } 194 } 195 } 196