1 /** 2 * Copyright (C) 2011 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.inject.grapher; 18 19 import com.google.common.collect.ImmutableList; 20 import com.google.common.collect.Lists; 21 import com.google.inject.Binding; 22 import com.google.inject.spi.ConstructorBinding; 23 import com.google.inject.spi.ConvertedConstantBinding; 24 import com.google.inject.spi.DefaultBindingTargetVisitor; 25 import com.google.inject.spi.Dependency; 26 import com.google.inject.spi.HasDependencies; 27 import com.google.inject.spi.InstanceBinding; 28 import com.google.inject.spi.LinkedKeyBinding; 29 import com.google.inject.spi.ProviderBinding; 30 import com.google.inject.spi.ProviderInstanceBinding; 31 import com.google.inject.spi.ProviderKeyBinding; 32 import java.util.Collection; 33 import java.util.List; 34 35 /** 36 * Default edge creator. 37 * 38 * @author bojand@google.com (Bojan Djordjevic) 39 */ 40 final class DefaultEdgeCreator implements EdgeCreator { 41 getEdges(Iterable<Binding<?>> bindings)42 @Override public Iterable<Edge> getEdges(Iterable<Binding<?>> bindings) { 43 List<Edge> edges = Lists.newArrayList(); 44 EdgeVisitor visitor = new EdgeVisitor(); 45 for (Binding<?> binding : bindings) { 46 edges.addAll(binding.acceptTargetVisitor(visitor)); 47 } 48 return edges; 49 } 50 51 /** 52 * {@link BindingTargetVisitor} that adds edges to the graph based on the visited {@link Binding}. 53 */ 54 private static final class EdgeVisitor 55 extends DefaultBindingTargetVisitor<Object, Collection<Edge>> { 56 57 /** 58 * Returns a dependency edge for each {@link Dependency} in the binding. These will be from the 59 * given node ID to the {@link Dependency}'s {@link Key}. 60 * 61 * @param nodeId ID of the node that should be the tail of the dependency 62 * edges 63 * @param binding {@link Binding} for the dependencies 64 */ newDependencyEdges( NodeId nodeId, T binding)65 private <T extends Binding<?> & HasDependencies> Collection<Edge> newDependencyEdges( 66 NodeId nodeId, T binding) { 67 ImmutableList.Builder<Edge> builder = ImmutableList.builder(); 68 for (Dependency<?> dependency : binding.getDependencies()) { 69 NodeId to = NodeId.newTypeId(dependency.getKey()); 70 builder.add(new DependencyEdge(nodeId, to, dependency.getInjectionPoint())); 71 } 72 return builder.build(); 73 } 74 75 /** 76 * Visitor for {@link ConstructorBinding}s. These are for classes that Guice will instantiate to 77 * satisfy injection requests. 78 */ visit(ConstructorBinding<?> binding)79 @Override public Collection<Edge> visit(ConstructorBinding<?> binding) { 80 return newDependencyEdges(NodeId.newTypeId(binding.getKey()), binding); 81 } 82 83 /** 84 * Visitor for {@link ConvertedConstantBinding}. The {@link Binding}'s {@link Key} will be of an 85 * annotated primitive type, and the value of {@link ConvertedConstantBinding#getSourceKey()} 86 * will be of a {@link String} with the same annotation. 87 */ visit(ConvertedConstantBinding<?> binding)88 @Override public Collection<Edge> visit(ConvertedConstantBinding<?> binding) { 89 return ImmutableList.<Edge>of(new BindingEdge(NodeId.newTypeId(binding.getKey()), 90 NodeId.newTypeId(binding.getSourceKey()), 91 BindingEdge.Type.CONVERTED_CONSTANT)); 92 } 93 94 /** 95 * Visitor for {@link InstanceBinding}. We then render any dependency edgess that the instance 96 * may have, which come either from {@link InjectionPoint}s (method and field) on the instance, 97 * or on {@link Dependency}s the instance declares through the {@link HasDependencies} 98 * interface. 99 */ visit(InstanceBinding<?> binding)100 @Override public Collection<Edge> visit(InstanceBinding<?> binding) { 101 return new ImmutableList.Builder<Edge>() 102 .add(new BindingEdge(NodeId.newTypeId(binding.getKey()), 103 NodeId.newInstanceId(binding.getKey()), 104 BindingEdge.Type.NORMAL)) 105 .addAll(newDependencyEdges(NodeId.newInstanceId(binding.getKey()), binding)) 106 .build(); 107 } 108 109 /** 110 * Visitor for {@link LinkedKeyBinding}. This is the standard {@link Binding} you get from 111 * binding an interface class to an implementation class. We draw a {@link BindingEdge} from 112 * the interface node to the node of the implementing class. 113 */ visit(LinkedKeyBinding<?> binding)114 @Override public Collection<Edge> visit(LinkedKeyBinding<?> binding) { 115 return ImmutableList.<Edge>of(new BindingEdge(NodeId.newTypeId(binding.getKey()), 116 NodeId.newTypeId(binding.getLinkedKey()), 117 BindingEdge.Type.NORMAL)); 118 } 119 120 /** 121 * Visitor for {@link ProviderBinding}. These {@link Binding}s arise from an 122 * {@link InjectionPoint} for the {@link Provider} interface. 123 */ visit(ProviderBinding<?> binding)124 @Override public Collection<Edge> visit(ProviderBinding<?> binding) { 125 return ImmutableList.<Edge>of(new BindingEdge(NodeId.newTypeId(binding.getKey()), 126 NodeId.newTypeId(binding.getProvidedKey()), BindingEdge.Type.PROVIDER)); 127 } 128 129 /** 130 * Same as {@link #visit(InstanceBinding)}, but the binding edge is 131 * {@link BindingEdge.Type#PROVIDER}. 132 */ visit(ProviderInstanceBinding<?> binding)133 @Override public Collection<Edge> visit(ProviderInstanceBinding<?> binding) { 134 return new ImmutableList.Builder<Edge>() 135 .add(new BindingEdge(NodeId.newTypeId(binding.getKey()), 136 NodeId.newInstanceId(binding.getKey()), BindingEdge.Type.PROVIDER)) 137 .addAll(newDependencyEdges(NodeId.newInstanceId(binding.getKey()), binding)) 138 .build(); 139 } 140 141 /** 142 * Same as {@link #visit(LinkedKeyBinding)}, but the binding edge is 143 * {@link BindingEdge.Type#PROVIDER}. 144 */ visit(ProviderKeyBinding<?> binding)145 @Override public Collection<Edge> visit(ProviderKeyBinding<?> binding) { 146 return ImmutableList.<Edge>of(new BindingEdge(NodeId.newTypeId(binding.getKey()), 147 NodeId.newTypeId(binding.getProviderKey()), BindingEdge.Type.PROVIDER)); 148 } 149 visitOther(Binding<?> binding)150 @Override public Collection<Edge> visitOther(Binding<?> binding) { 151 return ImmutableList.of(); 152 } 153 } 154 } 155