public ModuleDependencyTransformer(TypeLiteral<M> type) { final ModuleDescription annotation = type.getRawType().getAnnotation(ModuleDescription.class); if(annotation == null) { requiresKeys = ImmutableSet.of(); dependsKeys = followsKeys = ImmutableSet.of(); } else { requiresKeys = Keys.get(annotation.requires()); dependsKeys = Keys.optional(annotation.depends()); followsKeys = Keys.optional(annotation.follows()); } dependencies = Streams.concat(requiresKeys.stream(), dependsKeys.stream(), followsKeys.stream()) .map(Dependency::get) .collect(Collectors.toImmutableSet()); }
public static PassType newPassType(String name, Class<? extends Pass> cls) { ImmutableList.Builder<TypeLiteral<?>> inputs = ImmutableList.builder(); ImmutableList.Builder<TypeLiteral<?>> outputs = ImmutableList.builder(); InjectionPoint passCtor = InjectionPoint.forConstructorOf(cls); for (Dependency<?> dep : passCtor.getDependencies()) { Key key = dep.getKey(); if (key.getAnnotation() instanceof PassInput) { inputs.add(key.getTypeLiteral()); } else if (key.getAnnotation() instanceof PassOutput) { checkState(key.getTypeLiteral().getRawType() == Consumer.class); ParameterizedType parameterized = (ParameterizedType) key.getTypeLiteral().getType(); java.lang.reflect.Type outputType = parameterized.getActualTypeArguments()[0]; outputs.add(TypeLiteral.get(outputType)); } } return new PassType(name, cls, inputs.build(), outputs.build()); }
@Inject @Toolable @SuppressWarnings("unchecked") void initialize(Injector injector) { final Binding<T> realBinding = injector.getBinding(this.rewritten); final Provider<T> realProvider = injector.getProvider(realBinding.getKey()); // The proxy will be a sub type of the source type of the binding final Class<T> proxyType = (Class<T>) realBinding.getKey() .getTypeLiteral().getRawType(); this.dependencies = Collections.singleton( Dependency.get(this.rewritten)); this.ref = InstanceBuilder.forType(proxyType) .withConstructionStrategy(this.strategy) .dispatchTo(realProvider) .create(injector); }
EventualProvider( Invokable<T, ?> method, boolean exposedBinding, List<Dependency<ListenableFuture<?>>> dependencies, Key<ListenableFuture<?>> bindingKey, @Nullable Class<? extends Annotation> scopeAnnotation, Object source) { this.method = method; this.source = source; this.exposedBinding = exposedBinding; this.bindingKey = bindingKey; this.scopeAnnotation = scopeAnnotation; this.dependencies = ImmutableList.copyOf(dependencies); this.dependencySet = ImmutableSet.<Dependency<?>>builder() .addAll(dependencies) .add(Dependency.get(Key.get(Injector.class))) .add(Dependency.get(Key.get(type.getRawType()))) .build(); }
@Override public <T> void onProvision(ProvisionInvocation<T> provision) { for (DependencyAndSource dependencyAndSource : provision.getDependencyChain()) { Dependency<?> dependency = dependencyAndSource.getDependency(); if (dependency != null && key.equals(dependency.getKey())) { try { ProviderAdapter.pushContext(dependency.getInjectionPoint()); provision.provision(); } finally { ProviderAdapter.popContext(); } break; } } }
/** * Returns true if all dependencies are suitable for the optimized version of AssistedInject. The * optimized version caches the binding & uses a ThreadLocal Provider, so can only be applied if * the assisted bindings are immediately provided. This looks for hints that the values may be * lazily retrieved, by looking for injections of Injector or a Provider for the assisted values. */ private boolean isValidForOptimizedAssistedInject(Set<Dependency<?>> dependencies, Class<?> implementation, TypeLiteral<?> factoryType) { Set<Dependency<?>> badDeps = null; // optimization: create lazily for (Dependency<?> dep : dependencies) { if (isInjectorOrAssistedProvider(dep)) { if (badDeps == null) { badDeps = Sets.newHashSet(); } badDeps.add(dep); } } if (badDeps != null && !badDeps.isEmpty()) { logger.log(Level.WARNING, "AssistedInject factory {0} will be slow " + "because {1} has assisted Provider dependencies or injects the Injector. " + "Stop injecting @Assisted Provider<T> (instead use @Assisted T) " + "or Injector to speed things up. (It will be a ~6500% speed bump!) " + "The exact offending deps are: {2}", new Object[] {factoryType, implementation, badDeps} ); return false; } return true; }
/** * Returns true if all dependencies are suitable for the optimized version of AssistedInject. The * optimized version caches the binding & uses a ThreadLocal Provider, so can only be applied if * the assisted bindings are immediately provided. This looks for hints that the values may be * lazily retrieved, by looking for injections of Injector or a Provider for the assisted values. */ private boolean isValidForOptimizedAssistedInject( Set<Dependency<?>> dependencies, Class<?> implementation, TypeLiteral<?> factoryType) { Set<Dependency<?>> badDeps = null; // optimization: create lazily for (Dependency<?> dep : dependencies) { if (isInjectorOrAssistedProvider(dep)) { if (badDeps == null) { badDeps = Sets.newHashSet(); } badDeps.add(dep); } } if (badDeps != null && !badDeps.isEmpty()) { logger.log( Level.WARNING, "AssistedInject factory {0} will be slow " + "because {1} has assisted Provider dependencies or injects the Injector. " + "Stop injecting @Assisted Provider<T> (instead use @Assisted T) " + "or Injector to speed things up. (It will be a ~6500% speed bump!) " + "The exact offending deps are: {2}", new Object[] {factoryType, implementation, badDeps}); return false; } return true; }
public void testFactoryBindingDependencies() { Injector injector = Guice.createInjector( new AbstractModule() { @Override protected void configure() { bind(Double.class).toInstance(5.0d); bind(ColoredCarFactory.class) .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class)); } }); Binding<?> binding = injector.getBinding(ColoredCarFactory.class); HasDependencies hasDependencies = (HasDependencies) binding; assertEquals( ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(double.class))), hasDependencies.getDependencies()); }
@Override protected void doInitialize(InjectorImpl injector, Errors errors) throws ErrorsException { @SuppressWarnings("unchecked") K[] keysArray = (K[]) new Object[bindingSelection.getMapBindings().size()]; keys = keysArray; ImmutableSet.Builder<Dependency<?>> dependenciesBuilder = ImmutableSet.builder(); int i = 0; for (Map.Entry<K, Binding<V>> entry : bindingSelection.getMapBindings().entrySet()) { dependenciesBuilder.add(Dependency.get(entry.getValue().getKey())); keys[i] = entry.getKey(); i++; } ImmutableSet<Dependency<?>> localDependencies = dependenciesBuilder.build(); dependencies = localDependencies; List<Dependency<?>> dependenciesList = localDependencies.asList(); // We know the type because we built up our own sets of dependencies, it's just // that the interface uses a "?" generic @SuppressWarnings("unchecked") SingleParameterInjector<V>[] typedInjectors = (SingleParameterInjector<V>[]) injector.getParametersInjectors(dependenciesList, errors); injectors = typedInjectors; }
CheckedProviderMethod( Key<T> key, Method method, Object instance, ImmutableSet<Dependency<?>> dependencies, List<Provider<?>> parameterProviders, Class<? extends Annotation> scopeAnnotation, Class<? extends CheckedProvider> checkedProvider, List<TypeLiteral<?>> exceptionTypes, boolean scopeExceptions) { this.key = key; this.scopeAnnotation = scopeAnnotation; this.instance = instance; this.dependencies = dependencies; this.method = method; this.parameterProviders = parameterProviders; this.exposed = method.isAnnotationPresent(Exposed.class); this.checkedProvider = checkedProvider; this.exceptionTypes = exceptionTypes; this.scopeExceptions = scopeExceptions; method.setAccessible(true); }
@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, new ProvisionCallback<T>() { @Override public T call() throws InternalProvisionException { return doProvision(context, dependency); } }); } }
/** * Invoked by Guice at Injector-creation time to prepare providers for each * element in this set. At this time the set's size is known, but its * contents are only evaluated when get() is invoked. */ @Toolable @Inject void initialize(Injector injector) { List<Binding<T>> bindings = Lists.newArrayList(); List<Dependency<?>> dependencies = Lists.newArrayList(); for (Binding<?> entry : injector.findBindingsByType(elementType)) { if (keyMatches(entry.getKey())) { @SuppressWarnings("unchecked") // protected by findBindingsByType() Binding<T> binding = (Binding<T>) entry; bindings.add(binding); dependencies.add(Dependency.get(binding.getKey())); } } this.bindings = ImmutableList.copyOf(bindings); this.dependencies = ImmutableSet.copyOf(dependencies); this.permitDuplicates = permitsDuplicates(injector); this.binder = null; }
/** * We just want to make sure that multibinder's binding depends on each of its values. We don't * really care about the underlying structure of those bindings, which are implementation details. */ public void testMultibinderDependencies() { Injector injector = Guice.createInjector( new AbstractModule() { @Override protected void configure() { Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); multibinder.addBinding().toInstance("A"); multibinder.addBinding().to(Key.get(String.class, Names.named("b"))); bindConstant().annotatedWith(Names.named("b")).to("B"); } }); Binding<Set<String>> binding = injector.getBinding(new Key<Set<String>>() {}); HasDependencies withDependencies = (HasDependencies) binding; Set<String> elements = Sets.newHashSet(); for (Dependency<?> dependency : withDependencies.getDependencies()) { elements.add((String) injector.getInstance(dependency.getKey())); } assertEquals(ImmutableSet.of("A", "B"), elements); }
@Override protected T provision(javax.inject.Provider<? extends T> provider, Errors errors, Dependency<?> dependency, ConstructionContext<T> constructionContext) throws ErrorsException { try { Object o = super.provision(provider, errors, dependency, constructionContext); if (o != null && !rawType.isInstance(o)) { throw errors.subtypeNotProvided(providerType, rawType).toException(); } @SuppressWarnings("unchecked") // protected by isInstance() check above T t = (T) o; return t; } catch (RuntimeException e) { throw errors.errorInProvider(e).toException(); } }
@Override protected Optional<T> doProvision(InternalContext context, Dependency<?> currentDependency) throws InternalProvisionException { InternalFactory<? extends T> local = delegate; if (local == null) { return Optional.absent(); } Dependency<?> localDependency = targetDependency; T result; Dependency previous = context.pushDependency(localDependency, getSource()); try { // currentDependency is Optional<? super T>, so we really just need to set the target // dependency to ? super T, but we are currently setting it to T. We could hypothetically // make it easier for our delegate to generate proxies by modifying the dependency, but that // would also require us to rewrite the key on each call. So for now we don't do it. result = local.get(context, localDependency, false); } catch (InternalProvisionException ipe) { throw ipe.addSource(localDependency); } finally { context.popStateAndSetDependency(previous); } return Optional.fromNullable(result); }
/** @param method the method to invoke. It's return type must be the same type as {@code key}. */ private ProviderMethod( Key<T> key, Method method, Object instance, ImmutableSet<Dependency<?>> dependencies, Class<? extends Annotation> scopeAnnotation, Annotation annotation) { // We can be safely initialized eagerly since our bindings must exist statically and it is an // error for them not to. super(InitializationTiming.EAGER); this.key = key; this.scopeAnnotation = scopeAnnotation; this.instance = instance; this.dependencies = dependencies; this.method = method; this.exposed = method.isAnnotationPresent(Exposed.class); this.annotation = annotation; }
@Override protected T doProvision(InternalContext context, Dependency<?> dependency) throws InternalProvisionException { try { T t = doProvision(SingleParameterInjector.getAll(context, parameterInjectors)); if (t == null && !dependency.isNullable()) { InternalProvisionException.onNullInjectedIntoNonNullableDependency(getMethod(), dependency); } return t; } catch (IllegalAccessException e) { throw new AssertionError(e); } catch (InvocationTargetException userException) { Throwable cause = userException.getCause() != null ? userException.getCause() : userException; throw InternalProvisionException.errorInProvider(cause).addSource(getSource()); } }
@Override @SuppressWarnings("unchecked") public T get(InternalContext context, Dependency<?> dependency, boolean linked) throws InternalProvisionException { ConstructorInjector<T> localInjector = constructorInjector; if (localInjector == null) { throw new IllegalStateException("Constructor not ready"); } if (!linked && failIfNotLinked) { throw InternalProvisionException.jitDisabled(key); } // This may not actually be safe because it could return a super type of T (if that's all the // client needs), but it should be OK in practice thanks to the wonders of erasure. return (T) localInjector.construct(context, dependency, provisionCallback); }
@Override protected void doInitialize(InjectorImpl injector, Errors errors) { ImmutableMap.Builder<K, Set<Provider<V>>> multimapOfProvidersBuilder = ImmutableMap.builder(); ImmutableSet.Builder<Dependency<?>> dependenciesBuilder = ImmutableSet.builder(); for (Map.Entry<K, Set<Binding<V>>> entry : bindingSelection.getMultimapBindings().entrySet()) { ImmutableSet.Builder<Provider<V>> providersBuilder = ImmutableSet.builder(); for (Binding<V> binding : entry.getValue()) { providersBuilder.add(binding.getProvider()); dependenciesBuilder.add(Dependency.get(getKeyOfProvider(binding.getKey()))); } multimapOfProvidersBuilder.put(entry.getKey(), providersBuilder.build()); } multimapOfProviders = multimapOfProvidersBuilder.build(); dependencies = dependenciesBuilder.build(); }
/** * Adds a binding for T. Multiple calls to this are safe, and will be collapsed as duplicate * bindings. */ private void addDirectTypeBinding(Binder binder) { binder.bind(typeKey).toProvider(new RealOptionalBinderProviderWithDependencies<T>(typeKey) { public T get() { Optional<Provider<T>> optional = optionalProviderT.get(); if (optional.isPresent()) { return optional.get().get(); } // Let Guice handle blowing up if the injection point doesn't have @Nullable // (If it does have @Nullable, that's fine. This would only happen if // setBinding/setDefault themselves were bound to 'null'). return null; } public Set<Dependency<?>> getDependencies() { return dependencies; } }); }
public T get() { final Errors errors = new Errors(); try { T t = injector.callInContext(new ContextualCallable<T>() { public T call(InternalContext context) throws ErrorsException { Dependency dependency = context.getDependency(); // Always pretend that we are a linked binding, to support // scoping implicit bindings. If we are not actually a linked // binding, we'll fail properly elsewhere in the chain. return internalFactory.get(errors, context, dependency, true); } }); errors.throwIfNewErrors(0); return t; } catch (ErrorsException e) { throw new ProvisionException(errors.merge(e.getErrors()).getMessages()); } }
@Override protected T provision( javax.inject.Provider<? extends T> provider, Dependency<?> dependency, ConstructionContext<T> constructionContext) throws InternalProvisionException { try { Object o = super.provision(provider, dependency, constructionContext); if (o != null && !rawType.isInstance(o)) { throw InternalProvisionException.subtypeNotProvided(providerType, rawType); } @SuppressWarnings("unchecked") // protected by isInstance() check above T t = (T) o; return t; } catch (RuntimeException e) { throw InternalProvisionException.errorInProvider(e).addSource(source); } }
/** * Return all direct dependencies injected into the given type */ public static Stream<Dependency<?>> dependencies(Class<?> type) { return Stream.concat( Stream.of(InjectionPoint.forConstructorOf(type)), InjectionPoint.forInstanceMethodsAndFields(type).stream() ).flatMap(ip -> ip.getDependencies().stream()); }
public Provider<T> asProvider() { return new ProviderWithDependencies<T>() { @Override public T get() { return Injection.wrappingExceptions(asSupplier()); } @Override public Set<Dependency<?>> getDependencies() { return dependencies; } }; }
public DependencyCollector log(Logger logger, Level level) { logger.log(level, "Dumping all dependencies:"); for(Map.Entry<TypeLiteral<?>, Collection<InjectionPoint>> entry : injectionPointsByType().asMap().entrySet()) { logger.log(level, entry.getKey().toString()); for(InjectionPoint ip : entry.getValue()) { logger.log(level, " " + ip.getMember()); for(Dependency<?> dep : dependenciesByInjectionPoint().get(ip)) { logger.log(level, " " + dep); } } } return this; }
@Inject public MemberInjectingFactory(TypeLiteral<T> type, MembersInjector<T> injector) { this.type = type; this.injector = injector; this.injectionPoint = InjectionPoint.forConstructorOf(type); this.constructor = (Constructor<T>) injectionPoint.getMember(); this.constructor.setAccessible(true); dependencies.addAll(Dependency.forInjectionPoints(InjectionPoint.forInstanceMethodsAndFields(type))); }
private void analyzeDependencies(final Collection<Dependency<?>> dependencies) { for( final Dependency<?> d : dependencies ) { final Key<?> key = d.getKey(); InjectionPoint injectionPoint = d.getInjectionPoint(); if( injectionPoint != null && injectionPoint.isOptional() ) { continue; } if( key.getAnnotationType() == Assisted.class ) { continue; } TypeLiteral<?> typeLiteral = key.getTypeLiteral(); Class<?> rawType = typeLiteral.getRawType(); if( rawType == Injector.class ) { continue; } if( rawType == MembersInjector.class ) { Key<?> injectedKey = key .ofType(((ParameterizedType) typeLiteral.getType()).getActualTypeArguments()[0]); dependentKeys.add(injectedKey); analyzeImplementation(injectedKey.getTypeLiteral(), true); } else if( rawType == Provider.class ) { dependentKeys.add(key.ofType(((ParameterizedType) typeLiteral.getType()).getActualTypeArguments()[0])); } else { dependentKeys.add(key); } } }
ScopedProxyProvider(Key<T> sourceKey, Key<T> rewrittenKey, ConstructionStrategy strategy) { this.rewritten = rewrittenKey; this.strategy = strategy; this.dependencies = Collections.singleton( Dependency.get(Key.get(Injector.class))); }
private EventualProvider<?> providerFor(Invokable<T, ?> method, Errors methodErrors) { Annotation[] annotations = method.getAnnotations(); verifyMethodAccessibility(methodErrors, method, source); @Nullable Annotation bindingAnnotation = Annotations.findBindingAnnotation(methodErrors, method, annotations); verifyAbsenseOfScopeAnnotation(methodErrors, annotations, source); List<Dependency<ListenableFuture<?>>> dependencies = Lists.newArrayListWithCapacity(method.getParameters().size()); for (Parameter parameter : method.getParameters()) { dependencies.add(extractDependency(methodErrors, parameter)); } Key<ListenableFuture<?>> bindingKey; boolean exposedBinding = method.isAnnotationPresent(Exposed.class); if (isVoid(method)) { bindingKey = futureKey(TypeToken.of(Boolean.class), new BlackholedAnnotation()); exposedBinding = false; } else { bindingKey = futureKey(method.getReturnType(), bindingAnnotation); } return new EventualProvider<>( method, exposedBinding, dependencies, bindingKey, scopeAnnotation, source); }
Dependency<ListenableFuture<?>> extractDependency(Errors methodErrors, Parameter parameter) { @Nullable Annotation bindingAnnotation = Annotations.findBindingAnnotation( methodErrors, parameter.getDeclaringInvokable(), parameter.getAnnotations()); return Dependency.get(futureKey( parameter.getType(), bindingAnnotation)); }
private List<Provider<ListenableFuture<?>>> providersForDependencies(Injector injector) { List<Provider<ListenableFuture<?>>> providers = Lists.newArrayListWithCapacity(dependencies.size()); for (Dependency<ListenableFuture<?>> d : dependencies) { providers.add(injector.getProvider(d.getKey())); } return providers; }
@Nullable private static InjectionPoint findInjectionPoint(List<DependencyAndSource> dependencyChain) { if (dependencyChain.size() < 3) { new AssertionError("Provider is not included in the dependency chain").printStackTrace(); } // @Inject InjectionPoint is the last, so we can skip it for (int i = dependencyChain.size() - 2; i >= 0; i--) { final Dependency<?> dependency = dependencyChain.get(i).getDependency(); if (dependency == null) { return null; } final com.google.inject.spi.InjectionPoint spiInjectionPoint = dependency.getInjectionPoint(); if (spiInjectionPoint != null) { final TypeToken<?> source = TypeToken.of(spiInjectionPoint.getDeclaringType().getType()); final Member member = spiInjectionPoint.getMember(); final InjectionPoint injectionPoint; if (member instanceof Field) { final Field field = (Field) member; injectionPoint = new InjectionPoint(source, TypeToken.of(field.getGenericType()), field.getAnnotations()); } else if (member instanceof Executable) { final Executable executable = (Executable) member; final Annotation[][] parameterAnnotations = executable.getParameterAnnotations(); final Type[] parameterTypes = executable.getGenericParameterTypes(); final int index = dependency.getParameterIndex(); injectionPoint = new InjectionPoint(source, TypeToken.of(parameterTypes[index]), parameterAnnotations[index]); } else { throw new IllegalStateException("Unsupported Member type: " + member.getClass().getName()); } return injectionPoint; } } return null; }
private static String argumentList(HasDependencies binding) { StringBuilder builder = new StringBuilder(); for (Dependency<?> dependency : binding.getDependencies()) { builder.append(providerCall(dependency.getKey()) + ","); } if (0 < binding.getDependencies().size()) { builder.deleteCharAt(builder.length() - 1); } return builder.toString(); }
/** * Returns a new instance node for the given {@link Binding}. * * @param binding binding for the node to create * @param instance value of the instance * @return instance node for the given binding */ private <T extends Binding<?> & HasDependencies> InstanceNode newInstanceNode(T binding, Object instance) { Collection<Member> members = Lists.newArrayList(); for (Dependency<?> dependency : binding.getDependencies()) { InjectionPoint injectionPoint = dependency.getInjectionPoint(); if (injectionPoint != null) { members.add(injectionPoint.getMember()); } } return new InstanceNode(NodeId.newInstanceId(binding.getKey()), binding.getSource(), instance, members); }
/** Calculates all dependencies required by the implementation and constructor. */ private Set<Dependency<?>> getDependencies(InjectionPoint ctorPoint, TypeLiteral<?> implementation) { ImmutableSet.Builder<Dependency<?>> builder = ImmutableSet.builder(); builder.addAll(ctorPoint.getDependencies()); if (!implementation.getRawType().isInterface()) { for (InjectionPoint ip : InjectionPoint.forInstanceMethodsAndFields(implementation)) { builder.addAll(ip.getDependencies()); } } return builder.build(); }
@SuppressWarnings("unchecked") public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) throws ErrorsException { checkState(constructorInjector != null, "Constructor not ready"); if(failIfNotLinked && !linked) { throw errors.jitDisabled(key).toException(); } // This may not actually be safe because it could return a super type of T (if that's all the // client needs), but it should be OK in practice thanks to the wonders of erasure. return (T) constructorInjector.construct(errors, context, dependency.getKey().getTypeLiteral().getRawType(), allowCircularProxy, provisionCallback); }
/** Return all non-assisted dependencies. */ private Set<Dependency<?>> removeAssistedDeps(Set<Dependency<?>> deps) { ImmutableSet.Builder<Dependency<?>> builder = ImmutableSet.builder(); for (Dependency<?> dep : deps) { Class<?> annotationType = dep.getKey().getAnnotationType(); if (annotationType == null || !annotationType.equals(Assisted.class)) { builder.add(dep); } } return builder.build(); }
public T get(Errors errors, InternalContext context, Dependency dependency, boolean linked) throws ErrorsException { checkState(providerBinding != null, "not initialized"); context.pushState(providerKey, providerBinding.getSource()); try { errors = errors.withSource(providerKey); Provider<? extends T> provider = providerBinding.getInternalFactory().get( errors, context, dependency, true); return circularGet(provider, errors, context, dependency, linked, provisionCallback); } finally { context.popState(); } }