/*
* 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);
}
}