@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; } } }
@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; }
/** Returns the current dependency chain (all the state). */ public List<DependencyAndSource> getDependencyChain() { ImmutableList.Builder<DependencyAndSource> builder = ImmutableList.builder(); for (int i = 0; i < state.size(); i += 2) { builder.add(new DependencyAndSource( (Dependency<?>) state.get(i), state.get(i + 1))); } return builder.build(); }
public <T> void onProvision(ProvisionInvocation<T> provision) { List<Class<?>> actual = Lists.newArrayList(); for (DependencyAndSource dep : provision.getDependencyChain()) { actual.add(dep.getDependency().getKey().getRawType()); } assertEquals(expected, actual); provisionList.add(provision.getBinding().getKey().getRawType()); }
/** Sets the new current dependency & adds it to the state. */ public Dependency pushDependency(Dependency dependency, Object source) { Dependency previous = this.dependency; this.dependency = dependency; state.addLast(new DependencyAndSource(dependency, source)); return previous; }
private Module getBindings(LogInject<_Logger_> logInject, Class<_Logger_> loggerClass) { TypeLiteral<_Logger_> loggerType = TypeLiteral.get(loggerClass); GuiceLoggerProvider<_Logger_> provider = new GuiceLoggerProvider<>(); Predicate<Dependency<?>> matchesLogger = dependency -> loggerType.equals(dependency.getKey().getTypeLiteral()); return new AbstractModule() { @Override protected void configure() { ProvisionListener provisionListener = new ProvisionListener() { @Override public <_Target_> void onProvision(ProvisionInvocation<_Target_> provision) { Binding<_Target_> binding = provision.getBinding(); if (loggerType.equals(binding.getKey().getTypeLiteral())) { Dependency<?> loggerDependency; Stream<Dependency<?>> stream; stream = provision.getDependencyChain().stream().map(DependencyAndSource::getDependency); Iterator<Dependency<?>> dependencies = reverse(stream.collect(toList())).iterator(); if (dependencies.hasNext() && matchesLogger.test(loggerDependency = dependencies.next())) { InjectionPoint injectionPoint = loggerDependency.getInjectionPoint(); TypeLiteral<?> declaringType = injectionPoint.getDeclaringType(); TypeLiteral<?> targetType = null; if (dependencies.hasNext()) { TypeLiteral<?> typeLiteral = dependencies.next().getKey().getTypeLiteral(); if (declaringType.getRawType().isAssignableFrom(typeLiteral.getRawType())) { targetType = typeLiteral; } } Class<?> logger = (targetType != null? targetType:declaringType).getRawType(); BindingTargetVisitor<_Target_, Void> bindingTargetVisitor; bindingTargetVisitor = new DefaultBindingTargetVisitor<_Target_, Void>() { @Override public Void visit(ProviderInstanceBinding<? extends _Target_> instanceBinding) { if (provider.equals(instanceBinding.getUserSuppliedProvider())) { provider.setLogger(logInject.createLogger(logger)); } return null; } }; binding.acceptTargetVisitor(bindingTargetVisitor); } } } }; bind(loggerClass).toProvider(provider); bindListener(Matchers.any(), provisionListener); } }; }
@Override public List<DependencyAndSource> getDependencyChain() { return context.getDependencyChain(); }
/** Adds to the state without setting the dependency. */ public void pushState(Key<?> key, Object source) { state.addLast(new DependencyAndSource(key == null ? null : Dependency.get(key), source)); }
/** Returns the current dependency chain (all the state). */ public List<DependencyAndSource> getDependencyChain() { return ImmutableList.copyOf(state); }
/** * Provides an instance of {@link T} for a given binding and dependency. * The {@link InjectionPoint}s are available through the {@link DependencyAndSource} * objects. The last dependency in the list is the one being directly provided. * * Note carefully the cases in which {@link DependencyAndSource#getDependency} and * {@link Dependency#getInjectionPoint} can return null. */ protected abstract T getFor(Binding<T> binding, List<DependencyAndSource> dependencyChain);