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.DefaultBindingTargetVisitor;
24 import com.google.inject.spi.Dependency;
25 import com.google.inject.spi.HasDependencies;
26 import com.google.inject.spi.InjectionPoint;
27 import com.google.inject.spi.InstanceBinding;
28 import com.google.inject.spi.ProviderInstanceBinding;
29 
30 import java.lang.reflect.Member;
31 import java.util.Collection;
32 import java.util.List;
33 
34 /**
35  * Default node creator.
36  *
37  * @author bojand@google.com (Bojan Djordjevic)
38  */
39 final class DefaultNodeCreator implements NodeCreator {
getNodes(Iterable<Binding<?>> bindings)40   @Override public Iterable<Node> getNodes(Iterable<Binding<?>> bindings) {
41     List<Node> nodes = Lists.newArrayList();
42     NodeVisitor visitor = new NodeVisitor();
43     for (Binding<?> binding : bindings) {
44       nodes.addAll(binding.acceptTargetVisitor(visitor));
45     }
46     return nodes;
47   }
48 
49   /**
50    * {@link BindingTargetVisitor} that adds nodes to the graph based on the visited {@link Binding}.
51    */
52   private static final class NodeVisitor
53       extends DefaultBindingTargetVisitor<Object, Collection<Node>> {
54 
55     /** Returns a new interface node for the given {@link Binding}. */
newInterfaceNode(Binding<?> binding)56     private InterfaceNode newInterfaceNode(Binding<?> binding) {
57       return new InterfaceNode(NodeId.newTypeId(binding.getKey()), binding.getSource());
58     }
59 
60     /**
61      * Returns a new implementation node for the given binding.
62      *
63      * @param binding binding for the node to create
64      * @param members members to add to the node
65      * @return implementation node for the given binding
66      */
newImplementationNode(Binding<?> binding, Collection<Member> members)67     private ImplementationNode newImplementationNode(Binding<?> binding,
68         Collection<Member> members) {
69       return new ImplementationNode(NodeId.newTypeId(binding.getKey()), binding.getSource(),
70           members);
71     }
72 
73     /**
74      * Returns a new instance node for the given {@link Binding}.
75      *
76      * @param binding binding for the node to create
77      * @param instance value of the instance
78      * @return instance node for the given binding
79      */
newInstanceNode(T binding, Object instance)80     private <T extends Binding<?> & HasDependencies> InstanceNode newInstanceNode(T binding,
81         Object instance) {
82       Collection<Member> members = Lists.newArrayList();
83       for (Dependency<?> dependency : binding.getDependencies()) {
84         InjectionPoint injectionPoint = dependency.getInjectionPoint();
85 
86         if (injectionPoint != null) {
87           members.add(injectionPoint.getMember());
88         }
89       }
90       return new InstanceNode(NodeId.newInstanceId(binding.getKey()), binding.getSource(), instance,
91           members);
92     }
93 
94     /**
95      * Visitor for {@link ConstructorBinding}s. These are for classes that Guice will instantiate to
96      * satisfy injection requests.
97      */
visit(ConstructorBinding<?> binding)98     @Override public Collection<Node> visit(ConstructorBinding<?> binding) {
99       Collection<Member> members = Lists.newArrayList();
100       members.add(binding.getConstructor().getMember());
101       for (InjectionPoint injectionPoint : binding.getInjectableMembers()) {
102         members.add(injectionPoint.getMember());
103       }
104 
105       return ImmutableList.<Node>of(newImplementationNode(binding, members));
106     }
107 
108     /**
109      * Visitor for {@link InstanceBinding}. We render two nodes in this case: an interface node for
110      * the binding's {@link Key}, and then an implementation node for the instance {@link Object}
111      * itself.
112      */
visit(InstanceBinding<?> binding)113     @Override public Collection<Node> visit(InstanceBinding<?> binding) {
114       return ImmutableList.<Node>of(newInterfaceNode(binding), newInstanceNode(binding,
115           binding.getInstance()));
116     }
117 
118     /**
119      * Same as {@link #visit(InstanceBinding)}, but the binding edge is
120      * {@link BindingEdgeType#PROVIDER}.
121      */
visit(ProviderInstanceBinding<?> binding)122     @Override public Collection<Node> visit(ProviderInstanceBinding<?> binding) {
123       return ImmutableList.<Node>of(newInterfaceNode(binding), newInstanceNode(binding,
124           binding.getUserSuppliedProvider()));
125     }
126 
visitOther(Binding<?> binding)127     @Override public Collection<Node> visitOther(Binding<?> binding) {
128       return ImmutableList.<Node>of(newInterfaceNode(binding));
129     }
130   }
131 }
132