/* * Copyright (C) 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.errai.ioc.rebind.ioc.graph.impl; import static org.jboss.errai.ioc.rebind.ioc.graph.impl.ResolutionPriority.getMatchingPriority; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Produces; import org.jboss.errai.codegen.meta.MetaClass; import org.jboss.errai.codegen.meta.MetaClassMember; import org.jboss.errai.codegen.meta.MetaField; import org.jboss.errai.codegen.meta.MetaMethod; import org.jboss.errai.codegen.meta.MetaParameter; import org.jboss.errai.ioc.client.api.EntryPoint; import org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCProcessor; import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraph; import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraphBuilder; import org.jboss.errai.ioc.rebind.ioc.graph.api.Injectable; import org.jboss.errai.ioc.rebind.ioc.graph.api.InjectionSite; import org.jboss.errai.ioc.rebind.ioc.graph.api.Qualifier; import org.jboss.errai.ioc.rebind.ioc.graph.api.QualifierFactory; import org.jboss.errai.ioc.rebind.ioc.injector.api.InjectableProvider; import org.jboss.errai.ioc.rebind.ioc.injector.api.WiringElementType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; /** * @see DependencyGraphBuilder * @author Max Barkley <mbarkley@redhat.com> */ public final class DependencyGraphBuilderImpl implements DependencyGraphBuilder { private static final Logger logger = LoggerFactory.getLogger(DependencyGraphBuilder.class); private final QualifierFactory qualFactory; private final Map<InjectableHandle, InjectableReference> injectableReferences = new HashMap<>(); private final Multimap<MetaClass, InjectableReference> directInjectableReferencesByAssignableTypes = HashMultimap.create(); private final Map<String, Injectable> injectablesByName = new HashMap<>(); private final List<InjectableImpl> specializations = new ArrayList<>(); private final FactoryNameGenerator nameGenerator = new FactoryNameGenerator(); private final boolean async; public DependencyGraphBuilderImpl(final QualifierFactory qualFactory, final boolean async) { this.qualFactory = qualFactory; this.async = async; } @Override public Injectable addInjectable(final MetaClass injectedType, final Qualifier qualifier, final Predicate<List<InjectableHandle>> pathPredicate, final Class<? extends Annotation> literalScope, final InjectableType injectableType, final WiringElementType... wiringTypes) { final InjectableImpl injectable = new InjectableImpl(injectedType, qualifier, pathPredicate, nameGenerator.generateFor(injectedType, qualifier, injectableType), literalScope, injectableType, Arrays.asList(wiringTypes)); return registerNewInjectable(injectable); } private Injectable registerNewInjectable(final InjectableImpl injectable) { logAddedInjectable(injectable); final String factoryName = injectable.getFactoryName(); if (injectablesByName.containsKey(factoryName)) { GraphUtil.throwDuplicateConcreteInjectableException(factoryName, injectablesByName.get(factoryName), injectable); } injectablesByName.put(factoryName, injectable); if (injectable.wiringTypes.contains(WiringElementType.Specialization)) { specializations.add(injectable); } linkDirectInjectableReference(injectable); return injectable; } private void logAddedInjectable(final Injectable injectable) { logger.debug("Adding new injectable: {}", injectable); if (logger.isTraceEnabled()) { logger.trace("Injectable type: {}", injectable.getInjectableType()); logger.trace("Injectable wiring types: {}", injectable.getWiringElementTypes()); } } @Override public Injectable addExtensionInjectable(final MetaClass injectedType, final Qualifier qualifier, final Predicate<List<InjectableHandle>> pathPredicate, final InjectableProvider provider, final WiringElementType... wiringTypes) { final InjectableImpl injectable = new ExtensionInjectable(injectedType, qualifier, pathPredicate, nameGenerator.generateFor(injectedType, qualifier, InjectableType.Extension), null, InjectableType.Extension, Arrays.asList(wiringTypes), provider); return registerNewInjectable(injectable); } private void linkDirectInjectableReference(final InjectableImpl injectable) { final InjectableReference injectableReference = lookupInjectableReference(injectable.type, injectable.qualifier); injectableReference.linked.add(injectable); } private void processAssignableTypes(final InjectableReference injectableReference) { for (final MetaClass assignable : injectableReference.type.getAllSuperTypesAndInterfaces()) { try { directInjectableReferencesByAssignableTypes.put(assignable.getErased(), injectableReference); } catch (final Throwable t) { throw new RuntimeException("Error occurred adding the assignable type " + assignable.getFullyQualifiedName(), t); } } } private InjectableReference lookupInjectableReference(final MetaClass type, final Qualifier qualifier) { final InjectableHandle handle = new InjectableHandle(type, qualifier); InjectableReference injectableReference = injectableReferences.get(handle); if (injectableReference == null) { injectableReference = new InjectableReference(type, qualifier); injectableReferences.put(handle, injectableReference); processAssignableTypes(injectableReference); } return injectableReference; } private void addDependency(final Injectable injectable, final Dependency dependency) { assert (injectable instanceof InjectableImpl); if (InjectableType.Disabled.equals(injectable.getInjectableType()) && (!DependencyType.ProducerMember.equals(dependency.getDependencyType()) || !injectable.getDependencies().isEmpty())) { throw new RuntimeException("The injectable, " + injectable + ", is disabled." + " A disabled injectable may only have a single dependency if it is produced by a disabled bean."); } final InjectableImpl injectableAsImpl = (InjectableImpl) injectable; injectableAsImpl.dependencies.add(BaseDependency.class.cast(dependency)); } @Override public DependencyGraph createGraph(final ReachabilityStrategy strategy) { logger.debug("Creating dependency graph..."); resolveSpecializations(); linkInjectableReferences(); resolveDependencies(); validateInjectables(); removeUnreachableInjectables(strategy); logger.debug("Finished creating dependency graph."); return new DependencyGraphImpl(injectablesByName); } private Collection<Validator> createValidators() { final Collection<Validator> validators = new ArrayList<>(); validators.add(new CycleValidator()); if (async) { validators.add(new AsyncValidator()); } return validators; } private void resolveSpecializations() { logger.debug("Processing {} specializations...", specializations.size()); final Set<InjectableImpl> toBeRemoved = new HashSet<>(); GraphUtil.sortSuperTypesBeforeSubtypes(specializations); for (final InjectableImpl specialization : specializations) { if (specialization.injectableType.equals(InjectableType.Producer)) { resolveProducerSpecialization(specialization, toBeRemoved); } else { resolveTypeSpecialization(specialization, toBeRemoved); } } logger.debug("Removed {} beans that were specialized.", toBeRemoved.size()); logger.trace("Types removed by specialization: {}", toBeRemoved); injectablesByName.values().removeAll(toBeRemoved); } private void resolveProducerSpecialization(final InjectableImpl specialization, final Set<InjectableImpl> toBeRemoved) { final ProducerInstanceDependencyImpl producerMemberDep = GraphUtil.findProducerInstanceDep(specialization); if (producerMemberDep.producingMember instanceof MetaMethod) { final MetaMethod specializedMethod = GraphUtil.getOverridenMethod((MetaMethod) producerMemberDep.producingMember); final MetaClass specializingType = producerMemberDep.producingMember.getDeclaringClass(); if (specializedMethod != null && specializedMethod.isAnnotationPresent(Produces.class)) { updateLinksToSpecialized(specialization, toBeRemoved, specializedMethod, specializingType); } } else { throw new RuntimeException("Specialized producers can only be methods. Found " + producerMemberDep.producingMember + " in " + producerMemberDep.producingMember.getDeclaringClassName()); } } private void updateLinksToSpecialized(final InjectableImpl specialization, final Set<InjectableImpl> toBeRemoved, final MetaMethod specializedMethod, final MetaClass specializingType) { final MetaClass enclosingType = specializedMethod.getDeclaringClass(); final MetaClass producedType = specializedMethod.getReturnType().getErased(); /* * Need to copy this because the call to lookupInjectableReference may modify the collection. */ final Collection<InjectableReference> directInjectableReferencesOfProducedType = new ArrayList<>( directInjectableReferencesByAssignableTypes.get(producedType)); for (final InjectableReference injectable : directInjectableReferencesOfProducedType) { if (injectable.type.equals(producedType)) { final Iterator<InjectableBase> linkedIter = injectable.linked.iterator(); while (linkedIter.hasNext()) { final InjectableBase link = linkedIter.next(); if (link instanceof InjectableImpl) { final InjectableImpl concreteLink = (InjectableImpl) link; removeSpecializedAndSpecializingLinks(specialization, toBeRemoved, specializingType, enclosingType, linkedIter, concreteLink); } } injectable.linked.add(lookupInjectableReference(specialization.type, specialization.qualifier)); } } } private void removeSpecializedAndSpecializingLinks(final InjectableImpl specialization, final Set<InjectableImpl> toBeRemoved, final MetaClass specializingType, final MetaClass enclosingType, final Iterator<InjectableBase> linkedIter, final InjectableImpl linkedInjectable) { if (linkedInjectable.injectableType.equals(InjectableType.Producer)) { final MetaClass foundProducerType = GraphUtil.findProducerInstanceDep(linkedInjectable).injectable.type.getErased(); if (foundProducerType.equals(enclosingType.getErased()) || foundProducerType.equals(specializingType.getErased())) { linkedIter.remove(); } if (foundProducerType.equals(enclosingType.getErased())) { toBeRemoved.add(linkedInjectable); specialization.qualifier = qualFactory.combine(specialization.qualifier, linkedInjectable.qualifier); } } } private void resolveTypeSpecialization(final InjectableImpl specialization, final Set<InjectableImpl> toBeRemoved) { final MetaClass specializedType = specialization.type.getSuperClass().getErased(); for (final InjectableReference injectable : directInjectableReferencesByAssignableTypes.get(specializedType)) { if (injectable.type.equals(specializedType)) { if (!injectable.linked.isEmpty()) { updateSpecializedReferenceLinks(specialization, toBeRemoved, injectable); break; } } } } private void updateSpecializedReferenceLinks(final InjectableImpl specialization, final Set<InjectableImpl> toBeRemoved, final InjectableReference injectableReference) { assert injectableReference.linked.size() == 1 : "The injectable " + injectableReference + " should have one link but instead has:\n" + injectableReference.linked; final InjectableImpl specialized = (InjectableImpl) injectableReference.linked.iterator().next(); specialization.qualifier = qualFactory.combine(specialization.qualifier, specialized.qualifier); toBeRemoved.add(specialized); injectableReference.linked.clear(); injectableReference.linked.add(lookupInjectableReference(specialization.type, specialization.qualifier)); removeLinksToProducedTypes(specialized, toBeRemoved); } private void removeLinksToProducedTypes(final InjectableImpl specialized, final Set<InjectableImpl> toBeRemoved) { final Collection<InjectableReference> producedReferences = new ArrayList<>(); for (final MetaMethod method : specialized.type.getDeclaredMethodsAnnotatedWith(Produces.class)) { producedReferences.add(lookupInjectableReference(method.getReturnType(), qualFactory.forSource(method))); } for (final MetaField field : specialized.type.getDeclaredFields()) { if (field.isAnnotationPresent(Produces.class)) { producedReferences.add(lookupInjectableReference(field.getType(), qualFactory.forSource(field))); } } for (final InjectableReference reference : producedReferences) { final Iterator<InjectableBase> linkIter = reference.linked.iterator(); while (linkIter.hasNext()) { final InjectableBase link = linkIter.next(); if (link instanceof InjectableImpl && ((InjectableImpl) link).injectableType.equals(InjectableType.Producer)) { final InjectableImpl concreteLink = (InjectableImpl) link; final ProducerInstanceDependencyImpl producerMemberDep = GraphUtil.findProducerInstanceDep(concreteLink); if (producerMemberDep.producingMember.getDeclaringClass().equals(specialized.type)) { linkIter.remove(); toBeRemoved.add(concreteLink); } } } } } private void validateInjectables() { logger.debug("Validating dependency graph..."); final Collection<String> problems = new ArrayList<>(); final Collection<Validator> validators = createValidators(); for (final Injectable injectable : injectablesByName.values()) { for (final Validator validator : validators) { if (validator.canValidate(injectable)) { validator.validate(injectable, problems); } } } if (!problems.isEmpty()) { throw new RuntimeException(GraphUtil.combineProblemMessages(problems)); } } private void removeUnreachableInjectables(final ReachabilityStrategy strategy) { logger.debug("Removing unreachable injectables from dependency graph using {} strategy.", strategy); final Set<String> reachableNames = new HashSet<>(); final Queue<Injectable> processingQueue = new LinkedList<>(); final Predicate<Injectable> reachabilityRoot = reachabilityRootPredicate(strategy); for (final Injectable injectable : injectablesByName.values()) { if (reachabilityRoot.test(injectable) && !reachableNames.contains(injectable.getFactoryName()) && !InjectableType.Disabled.equals(injectable.getInjectableType())) { processingQueue.add(injectable); do { final Injectable processedInjectable = processingQueue.poll(); reachableNames.add(processedInjectable.getFactoryName()); logger.trace("Marked as reachable: {}", processedInjectable); for (final Dependency dep : processedInjectable.getDependencies()) { final Injectable resolvedDep = GraphUtil.getResolvedDependency(dep, processedInjectable); if (!reachableNames.contains(resolvedDep.getFactoryName())) { processingQueue.add(resolvedDep); } } } while (processingQueue.size() > 0); } } final int initialSize = injectablesByName.size(); injectablesByName.keySet().retainAll(reachableNames); logger.debug("Removed {} unreachable injectables.", initialSize - injectablesByName.size()); } private Predicate<Injectable> reachabilityRootPredicate(final ReachabilityStrategy strategy) { switch (strategy) { case All: return inj -> true; case Annotated: return inj -> !inj.getWiringElementTypes().contains(WiringElementType.Simpleton); case Aggressive: return inj -> EntryPoint.class.equals(inj.getScope()) || inj.getWiringElementTypes().contains(WiringElementType.JsType); default: throw new RuntimeException("Unrecognized reachability strategy, " + strategy.toString()); } } private void resolveDependencies() { logger.debug("Resolving dependencies for {} injectables...", injectablesByName.size()); final Set<Injectable> visited = new HashSet<>(); final Set<String> transientInjectableNames = new HashSet<>(); final List<String> dependencyProblems = new ArrayList<>(); final Map<String, Injectable> customProvidedInjectables = new IdentityHashMap<>(); for (final Injectable injectable : injectablesByName.values()) { if (injectable.isExtension()) { transientInjectableNames.add(injectable.getFactoryName()); } if (!visited.contains(injectable)) { logger.debug("Resolving {} dependencies for: {}", injectable.getDependencies().size(), injectable); for (final Dependency dep : injectable.getDependencies()) { resolveDependency(BaseDependency.as(dep), injectable, dependencyProblems, customProvidedInjectables); } } } injectablesByName.keySet().removeAll(transientInjectableNames); injectablesByName.putAll(customProvidedInjectables); if (!dependencyProblems.isEmpty()) { throw new RuntimeException(GraphUtil.buildMessageFromProblems(dependencyProblems)); } } private Injectable resolveDependency(final BaseDependency dep, final Injectable depOwner, final Collection<String> problems, final Map<String, Injectable> customProvidedInjectables) { if (dep.injectable.resolution != null) { return dep.injectable.resolution; } logger.trace("Resolving dependency: {}", dep); final Multimap<ResolutionPriority, InjectableImpl> resolvedByPriority = traverseLinks(dep.injectable); final Iterable<ResolutionPriority> priorities; final boolean reportProblems; if (InjectableType.Disabled.equals(depOwner.getInjectableType())) { priorities = Collections.singleton(ResolutionPriority.Disabled); reportProblems = false; } else { priorities = ResolutionPriority.enabledValues(); reportProblems = true; } // Iterates through priorities from highest to lowest. for (final ResolutionPriority priority : priorities) { if (resolvedByPriority.containsKey(priority)) { final Collection<InjectableImpl> resolved = resolvedByPriority.get(priority); if (resolved.size() > 1) { if (reportProblems) { problems.add(GraphUtil.ambiguousDependencyMessage(dep, depOwner, new ArrayList<>(resolved))); } return null; } else { final Injectable injectable = maybeProcessAsExtension(dep, depOwner, customProvidedInjectables, resolvedByPriority, resolved); logger.trace("Resolved dependency: {}", injectable); return (dep.injectable.resolution = injectable); } } } if (reportProblems) { final Collection<Injectable> resolvedDisabledInjectables = resolvedByPriority .get(ResolutionPriority.Disabled) .stream() .map(inj -> getRootDisabledInjectable(inj, problems, customProvidedInjectables)) .collect(Collectors.toList()); problems.add(GraphUtil.unsatisfiedDependencyMessage(dep, depOwner, resolvedDisabledInjectables)); } return null; } private Injectable maybeProcessAsExtension(final BaseDependency dep, final Injectable depOwner, final Map<String, Injectable> customProvidedInjectables, final Multimap<ResolutionPriority, InjectableImpl> resolvedByPriority, final Collection<InjectableImpl> resolved) { Injectable injectable = resolved.iterator().next(); if (injectable.isExtension()) { final ExtensionInjectable providedInjectable = (ExtensionInjectable) injectable; final Collection<Injectable> otherResolvedInjectables = new ArrayList<>(resolvedByPriority.values()); otherResolvedInjectables.remove(injectable); final InjectionSite site = new InjectionSite(depOwner.getInjectedType(), dep, otherResolvedInjectables); injectable = providedInjectable.provider.getInjectable(site, nameGenerator); customProvidedInjectables.put(injectable.getFactoryName(), injectable); dep.injectable = GraphUtil.copyInjectableReference(dep.injectable); } return injectable; } private Multimap<ResolutionPriority, InjectableImpl> traverseLinks(final InjectableReference dep) { final Multimap<ResolutionPriority, InjectableImpl> resolvedByPriority = HashMultimap.create(); final LinkedList<InjectableHandle> handleStack = new LinkedList<>(); final LinkedList<Iterator<InjectableBase>> linkStack = new LinkedList<>(); handleStack.addLast(dep.getHandle()); linkStack.addLast(dep.linked.iterator()); do { final Iterator<InjectableBase> iter = linkStack.getLast(); if (iter.hasNext()) { final InjectableBase link = iter.next(); if (link instanceof InjectableReference) { logger.trace("Adding linked reference to resolution stack: {}", link); handleStack.addLast(link.getHandle()); if (isRawType(link.type)) { /* * SPECIAL CASE: * Java types with the relation "assignableTo" would form an ordering of types, * EXCEPT that raw types are assignable to any parameterization and vice-versa. * * This breaks anti-symmetry (A<B> assignableTo A and A assignableTo A<B> but A != A<B>) * and transitivity (for unrelated B and C, A<B> assignableTo A assignableTo A<C> but NOT * A<B> assignableTo A<C> since NOT B assignableTo C). * * As a consequence, following reference links from a raw type can lead to cycles (from lack of anti-symmetry) * or incorrect resolution of parameterized types (from lack of transitivity). * * The only time following reference links from a raw type is acceptable is when they * are at the beginning of a path being traversed (since then we really do want to find any possible * parameterization, and when we arrive back at the same raw-typed reference we will ignore the reference * links that we have already traversed, which avoids the possibility of an endless cycle). */ linkStack.addLast(getIteratorOfRawTypedInjectableLinks(link)); } else { linkStack.addLast(((InjectableReference) link).linked.iterator()); } } else if (link instanceof InjectableImpl) { final InjectableImpl resolvedInjectable = (InjectableImpl) link; if (resolvedInjectable.pathPredicate.test(handleStack)) { logger.trace("Adding linked injectable to resolution results: {}", link); resolvedByPriority.put(getMatchingPriority(resolvedInjectable), resolvedInjectable); } else { logger.trace("Rejecting linked injectable from resolution results based on path predicate: {}", link); } } } else { handleStack.removeLast(); linkStack.removeLast(); } } while (!linkStack.isEmpty()); logger.trace("Finished processing resolution stack. Resolved {} injectables.", resolvedByPriority.size()); return resolvedByPriority; } private Iterator<InjectableBase> getIteratorOfRawTypedInjectableLinks(final InjectableBase link) { final List<InjectableBase> injectableLinks = ((InjectableReference) link) .linked .stream() .filter(l -> l instanceof InjectableImpl) .filter(l -> isRawType(l.type)) .collect(Collectors.toList()); final Iterator<InjectableBase> injectablesInterator = injectableLinks.iterator(); return injectablesInterator; } private boolean isRawType(final MetaClass type) { // Guaranteed to be true for all raw types in all MetaClass impls return type == type.getErased(); } private Injectable getRootDisabledInjectable(Injectable inj, final Collection<String> problems, final Map<String, Injectable> customProvidedInjectables) { while (inj.getDependencies().size() == 1) { final Dependency dep = inj.getDependencies().iterator().next(); if (DependencyType.ProducerMember.equals(dep.getDependencyType())) { inj = resolveDependency((BaseDependency) dep, inj, problems, customProvidedInjectables); } } return inj; } private void linkInjectableReferences() { logger.debug("Linking {} references in dependencies...", injectableReferences.size()); final Set<InjectableReference> linked = new HashSet<>(injectableReferences.size()); for (final Injectable injectable : injectablesByName.values()) { for (final Dependency dep : injectable.getDependencies()) { final BaseDependency baseDep = BaseDependency.as(dep); if (!linked.contains(baseDep.injectable)) { logger.debug("Processing dependency: {}", baseDep); linkInjectableReference(baseDep.injectable); linked.add(baseDep.injectable); } } } } private void linkInjectableReference(final InjectableReference injectableReference) { final Collection<InjectableReference> candidates = directInjectableReferencesByAssignableTypes .get(injectableReference.type.getErased()); logger.debug("Found {} candidate references.", candidates.size()); for (final InjectableReference candidate : candidates) { if (GraphUtil.candidateSatisfiesInjectable(injectableReference, candidate)) { logger.trace("Candidate has been linked: {}", candidate); injectableReference.linked.add(candidate); } } } private InjectableReference createStaticMemberInjectable(final MetaClass producerType, final MetaClassMember member) { final InjectableReference retVal = new InjectableReference(producerType, qualFactory.forUniversallyQualified()); retVal.resolution = new InjectableImpl(producerType, qualFactory.forUniversallyQualified(), IOCProcessor.ANY, "", ApplicationScoped.class, InjectableType.Static, Collections.<WiringElementType> emptyList()); return retVal; } @Override public void addFieldDependency(final Injectable concreteInjectable, final MetaClass type, final Qualifier qualifier, final MetaField dependentField) { final InjectableReference injectableReference = lookupInjectableReference(type, qualifier); final FieldDependency dep = new FieldDependencyImpl(injectableReference, dependentField); addDependency(concreteInjectable, dep); } @Override public void addConstructorDependency(final Injectable concreteInjectable, final MetaClass type, final Qualifier qualifier, final int paramIndex, final MetaParameter param) { final InjectableReference injectableReference = lookupInjectableReference(type, qualifier); final ParamDependency dep = new ParamDependencyImpl(injectableReference, DependencyType.Constructor, paramIndex, param); addDependency(concreteInjectable, dep); } @Override public void addProducerParamDependency(final Injectable concreteInjectable, final MetaClass type, final Qualifier qualifier, final int paramIndex, final MetaParameter param) { final InjectableReference injectableReference = lookupInjectableReference(type, qualifier); final ParamDependency dep = new ParamDependencyImpl(injectableReference, DependencyType.ProducerParameter, paramIndex, param); addDependency(concreteInjectable, dep); } @Override public void addProducerMemberDependency(final Injectable concreteInjectable, final MetaClass type, final Qualifier qualifier, final MetaClassMember producingMember) { final InjectableReference injectableReference = lookupInjectableReference(type, qualifier); final ProducerInstanceDependency dep = new ProducerInstanceDependencyImpl(injectableReference, DependencyType.ProducerMember, producingMember); addDependency(concreteInjectable, dep); } @Override public void addProducerMemberDependency(final Injectable producedInjectable, final MetaClass producerType, final MetaClassMember member) { final InjectableReference abstractInjectable = createStaticMemberInjectable(producerType, member); final ProducerInstanceDependency dep = new ProducerInstanceDependencyImpl( abstractInjectable, DependencyType.ProducerMember, member); addDependency(producedInjectable, dep); } @Override public void addSetterMethodDependency(final Injectable concreteInjectable, final MetaClass type, final Qualifier qualifier, final MetaMethod setter) { final InjectableReference injectableReference = lookupInjectableReference(type, qualifier); final SetterParameterDependency dep = new SetterParameterDependencyImpl(injectableReference, setter); addDependency(concreteInjectable, dep); } @Override public void addDisposesMethodDependency(final Injectable concreteInjectable, final MetaClass type, final Qualifier qualifier, final MetaMethod disposer) { final InjectableReference injectableReference = lookupInjectableReference(type, qualifier); final DisposerMethodDependency dep = new DisposerMethodDependencyImpl(injectableReference, disposer); addDependency(concreteInjectable, dep); } @Override public void addDisposesParamDependency(final Injectable concreteInjectable, final MetaClass type, final Qualifier qualifier, final Integer index, final MetaParameter param) { final InjectableReference injectableReference = lookupInjectableReference(type, qualifier); final ParamDependency dep = new ParamDependencyImpl(injectableReference, DependencyType.DisposerParameter, index, param); addDependency(concreteInjectable, dep); } }