• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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