• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2014 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.multibindings;
18 
19 import com.google.common.base.Objects;
20 import com.google.inject.Binding;
21 import com.google.inject.Injector;
22 import com.google.inject.Scope;
23 import com.google.inject.Scopes;
24 import com.google.inject.TypeLiteral;
25 import com.google.inject.spi.BindingScopingVisitor;
26 import com.google.inject.spi.ConstructorBinding;
27 import com.google.inject.spi.ConvertedConstantBinding;
28 import com.google.inject.spi.DefaultBindingTargetVisitor;
29 import com.google.inject.spi.ExposedBinding;
30 import com.google.inject.spi.InstanceBinding;
31 import com.google.inject.spi.LinkedKeyBinding;
32 import com.google.inject.spi.ProviderBinding;
33 import com.google.inject.spi.ProviderInstanceBinding;
34 import com.google.inject.spi.ProviderKeyBinding;
35 import com.google.inject.spi.UntargettedBinding;
36 
37 import java.lang.annotation.Annotation;
38 
39 /**
40  * Visits bindings to return a {@code IndexedBinding} that can be used to emulate the binding
41  * deduplication that Guice internally performs.
42  */
43 class Indexer extends DefaultBindingTargetVisitor<Object, Indexer.IndexedBinding>
44     implements BindingScopingVisitor<Object> {
45   enum BindingType {
46     INSTANCE,
47     PROVIDER_INSTANCE,
48     PROVIDER_KEY,
49     LINKED_KEY,
50     UNTARGETTED,
51     CONSTRUCTOR,
52     CONSTANT,
53     EXPOSED,
54     PROVIDED_BY,
55   }
56 
57   static class IndexedBinding {
58     final String annotationName;
59     final Element.Type annotationType;
60     final TypeLiteral<?> typeLiteral;
61     final Object scope;
62     final BindingType type;
63     final Object extraEquality;
64 
IndexedBinding(Binding<?> binding, BindingType type, Object scope, Object extraEquality)65     IndexedBinding(Binding<?> binding, BindingType type, Object scope, Object extraEquality) {
66       this.scope = scope;
67       this.type = type;
68       this.extraEquality = extraEquality;
69       this.typeLiteral = binding.getKey().getTypeLiteral();
70       Element annotation = (Element) binding.getKey().getAnnotation();
71       this.annotationName = annotation.setName();
72       this.annotationType = annotation.type();
73     }
74 
equals(Object obj)75     @Override public boolean equals(Object obj) {
76       if (!(obj instanceof IndexedBinding)) {
77         return false;
78       }
79       IndexedBinding o = (IndexedBinding) obj;
80       return type == o.type
81           && Objects.equal(scope, o.scope)
82           && typeLiteral.equals(o.typeLiteral)
83           && annotationType == o.annotationType
84           && annotationName.equals(o.annotationName)
85           && Objects.equal(extraEquality, o.extraEquality);
86     }
87 
hashCode()88     @Override public int hashCode() {
89       return Objects.hashCode(type, scope, typeLiteral, annotationType, annotationName,
90           extraEquality);
91     }
92   }
93 
94   final Injector injector;
95 
Indexer(Injector injector)96   Indexer(Injector injector) {
97     this.injector = injector;
98   }
99 
isIndexable(Binding<?> binding)100   boolean isIndexable(Binding<?> binding) {
101     return binding.getKey().getAnnotation() instanceof Element;
102   }
103 
scope(Binding<?> binding)104   private Object scope(Binding<?> binding) {
105     return binding.acceptScopingVisitor(this);
106   }
107 
visit(ConstructorBinding<? extends Object> binding)108   @Override public Indexer.IndexedBinding visit(ConstructorBinding<? extends Object> binding) {
109     return new Indexer.IndexedBinding(binding, BindingType.CONSTRUCTOR, scope(binding),
110         binding.getConstructor());
111   }
112 
visit( ConvertedConstantBinding<? extends Object> binding)113   @Override public Indexer.IndexedBinding visit(
114       ConvertedConstantBinding<? extends Object> binding) {
115     return new Indexer.IndexedBinding(binding, BindingType.CONSTANT, scope(binding),
116         binding.getValue());
117   }
118 
visit(ExposedBinding<? extends Object> binding)119   @Override public Indexer.IndexedBinding visit(ExposedBinding<? extends Object> binding) {
120     return new Indexer.IndexedBinding(binding, BindingType.EXPOSED, scope(binding), binding);
121   }
122 
visit(InstanceBinding<? extends Object> binding)123   @Override public Indexer.IndexedBinding visit(InstanceBinding<? extends Object> binding) {
124     return new Indexer.IndexedBinding(binding, BindingType.INSTANCE, scope(binding),
125         binding.getInstance());
126   }
127 
visit(LinkedKeyBinding<? extends Object> binding)128   @Override public Indexer.IndexedBinding visit(LinkedKeyBinding<? extends Object> binding) {
129     return new Indexer.IndexedBinding(binding, BindingType.LINKED_KEY, scope(binding),
130         binding.getLinkedKey());
131   }
132 
visit(ProviderBinding<? extends Object> binding)133   @Override public Indexer.IndexedBinding visit(ProviderBinding<? extends Object> binding) {
134     return new Indexer.IndexedBinding(binding, BindingType.PROVIDED_BY, scope(binding),
135         injector.getBinding(binding.getProvidedKey()));
136   }
137 
visit(ProviderInstanceBinding<? extends Object> binding)138   @Override public Indexer.IndexedBinding visit(ProviderInstanceBinding<? extends Object> binding) {
139     return new Indexer.IndexedBinding(binding, BindingType.PROVIDER_INSTANCE, scope(binding),
140         binding.getUserSuppliedProvider());
141   }
142 
visit(ProviderKeyBinding<? extends Object> binding)143   @Override public Indexer.IndexedBinding visit(ProviderKeyBinding<? extends Object> binding) {
144     return new Indexer.IndexedBinding(binding, BindingType.PROVIDER_KEY, scope(binding),
145         binding.getProviderKey());
146   }
147 
visit(UntargettedBinding<? extends Object> binding)148   @Override public Indexer.IndexedBinding visit(UntargettedBinding<? extends Object> binding) {
149     return new Indexer.IndexedBinding(binding, BindingType.UNTARGETTED, scope(binding), null);
150   }
151 
152   private static final Object EAGER_SINGLETON = new Object();
153 
visitEagerSingleton()154   @Override public Object visitEagerSingleton() {
155     return EAGER_SINGLETON;
156   }
157 
visitNoScoping()158   @Override public Object visitNoScoping() {
159     return Scopes.NO_SCOPE;
160   }
161 
visitScope(Scope scope)162   @Override public Object visitScope(Scope scope) {
163     return scope;
164   }
165 
visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation)166   @Override public Object visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
167     return scopeAnnotation;
168   }
169 }
170