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 42 @Override getEdges(Iterable<Binding<?>> bindings)43 public Iterable<Edge> getEdges(Iterable<Binding<?>> bindings) { 44 List<Edge> edges = Lists.newArrayList(); 45 EdgeVisitor visitor = new EdgeVisitor(); 46 for (Binding<?> binding : bindings) { 47 edges.addAll(binding.acceptTargetVisitor(visitor)); 48 } 49 return edges; 50 } 51 52 /** 53 * {@link BindingTargetVisitor} that adds edges to the graph based on the visited {@link Binding}. 54 */ 55 private static final class EdgeVisitor 56 extends DefaultBindingTargetVisitor<Object, Collection<Edge>> { 57 58 /** 59 * Returns a dependency edge for each {@link Dependency} in the binding. These will be from the 60 * given node ID to the {@link Dependency}'s {@link Key}. 61 * 62 * @param nodeId ID of the node that should be the tail of the dependency 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 */ 79 @Override visit(ConstructorBinding<?> binding)80 public Collection<Edge> visit(ConstructorBinding<?> binding) { 81 return newDependencyEdges(NodeId.newTypeId(binding.getKey()), binding); 82 } 83 84 /** 85 * Visitor for {@link ConvertedConstantBinding}. The {@link Binding}'s {@link Key} will be of an 86 * annotated primitive type, and the value of {@link ConvertedConstantBinding#getSourceKey()} 87 * will be of a {@link String} with the same annotation. 88 */ 89 @Override visit(ConvertedConstantBinding<?> binding)90 public Collection<Edge> visit(ConvertedConstantBinding<?> binding) { 91 return ImmutableList.<Edge>of( 92 new BindingEdge( 93 NodeId.newTypeId(binding.getKey()), 94 NodeId.newTypeId(binding.getSourceKey()), 95 BindingEdge.Type.CONVERTED_CONSTANT)); 96 } 97 98 /** 99 * Visitor for {@link InstanceBinding}. We then render any dependency edgess that the instance 100 * may have, which come either from {@link InjectionPoint}s (method and field) on the instance, 101 * or on {@link Dependency}s the instance declares through the {@link HasDependencies} 102 * interface. 103 */ 104 @Override visit(InstanceBinding<?> binding)105 public Collection<Edge> visit(InstanceBinding<?> binding) { 106 return new ImmutableList.Builder<Edge>() 107 .add( 108 new BindingEdge( 109 NodeId.newTypeId(binding.getKey()), 110 NodeId.newInstanceId(binding.getKey()), 111 BindingEdge.Type.NORMAL)) 112 .addAll(newDependencyEdges(NodeId.newInstanceId(binding.getKey()), binding)) 113 .build(); 114 } 115 116 /** 117 * Visitor for {@link LinkedKeyBinding}. This is the standard {@link Binding} you get from 118 * binding an interface class to an implementation class. We draw a {@link BindingEdge} from the 119 * interface node to the node of the implementing class. 120 */ 121 @Override visit(LinkedKeyBinding<?> binding)122 public Collection<Edge> visit(LinkedKeyBinding<?> binding) { 123 return ImmutableList.<Edge>of( 124 new BindingEdge( 125 NodeId.newTypeId(binding.getKey()), 126 NodeId.newTypeId(binding.getLinkedKey()), 127 BindingEdge.Type.NORMAL)); 128 } 129 130 /** 131 * Visitor for {@link ProviderBinding}. These {@link Binding}s arise from an {@link 132 * InjectionPoint} for the {@link Provider} interface. 133 */ 134 @Override visit(ProviderBinding<?> binding)135 public Collection<Edge> visit(ProviderBinding<?> binding) { 136 return ImmutableList.<Edge>of( 137 new BindingEdge( 138 NodeId.newTypeId(binding.getKey()), 139 NodeId.newTypeId(binding.getProvidedKey()), 140 BindingEdge.Type.PROVIDER)); 141 } 142 143 /** 144 * Same as {@link #visit(InstanceBinding)}, but the binding edge is {@link 145 * BindingEdge.Type#PROVIDER}. 146 */ 147 @Override visit(ProviderInstanceBinding<?> binding)148 public Collection<Edge> visit(ProviderInstanceBinding<?> binding) { 149 return new ImmutableList.Builder<Edge>() 150 .add( 151 new BindingEdge( 152 NodeId.newTypeId(binding.getKey()), 153 NodeId.newInstanceId(binding.getKey()), 154 BindingEdge.Type.PROVIDER)) 155 .addAll(newDependencyEdges(NodeId.newInstanceId(binding.getKey()), binding)) 156 .build(); 157 } 158 159 /** 160 * Same as {@link #visit(LinkedKeyBinding)}, but the binding edge is {@link 161 * BindingEdge.Type#PROVIDER}. 162 */ 163 @Override visit(ProviderKeyBinding<?> binding)164 public Collection<Edge> visit(ProviderKeyBinding<?> binding) { 165 return ImmutableList.<Edge>of( 166 new BindingEdge( 167 NodeId.newTypeId(binding.getKey()), 168 NodeId.newTypeId(binding.getProviderKey()), 169 BindingEdge.Type.PROVIDER)); 170 } 171 172 @Override visitOther(Binding<?> binding)173 public Collection<Edge> visitOther(Binding<?> binding) { 174 return ImmutableList.of(); 175 } 176 } 177 } 178