• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2007 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.assistedinject;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 
21 import com.google.inject.ConfigurationException;
22 import com.google.inject.Injector;
23 import com.google.inject.Key;
24 import com.google.inject.Provider;
25 import com.google.inject.internal.Annotations;
26 
27 import java.lang.annotation.Annotation;
28 import java.lang.reflect.ParameterizedType;
29 import java.lang.reflect.Type;
30 
31 /**
32  * Models a method or constructor parameter.
33  *
34  * @author jmourits@google.com (Jerome Mourits)
35  * @author jessewilson@google.com (Jesse Wilson)
36  */
37 class Parameter {
38 
39   private final Type type;
40   private final boolean isAssisted;
41   private final Annotation bindingAnnotation;
42   private final boolean isProvider;
43 
44   private volatile Provider<? extends Object> provider;
45 
Parameter(Type type, Annotation[] annotations)46   public Parameter(Type type, Annotation[] annotations) {
47     this.type = type;
48     this.bindingAnnotation = getBindingAnnotation(annotations);
49     this.isAssisted = hasAssistedAnnotation(annotations);
50     this.isProvider = isProvider(type);
51   }
52 
isProvidedByFactory()53   public boolean isProvidedByFactory() {
54     return isAssisted;
55   }
56 
getType()57   public Type getType() {
58     return type;
59   }
60 
61   @Override
toString()62   public String toString() {
63     StringBuilder result = new StringBuilder();
64     if (isAssisted) {
65       result.append("@Assisted ");
66     }
67     if (bindingAnnotation != null) {
68       result.append(bindingAnnotation).append(" ");
69     }
70     return result.append(type).toString();
71   }
72 
hasAssistedAnnotation(Annotation[] annotations)73   private boolean hasAssistedAnnotation(Annotation[] annotations) {
74     for (Annotation annotation : annotations) {
75       if (annotation.annotationType().equals(Assisted.class)) {
76         return true;
77       }
78     }
79     return false;
80   }
81 
82   /**
83    * Returns the Guice {@link Key} for this parameter.
84    */
getValue(Injector injector)85   public Object getValue(Injector injector) {
86     if (null == provider) {
87       synchronized (this) {
88         if (null == provider) {
89           provider = isProvider
90               ? injector.getProvider(getBindingForType(getProvidedType(type)))
91               : injector.getProvider(getPrimaryBindingKey());
92         }
93       }
94     }
95 
96     return isProvider ? provider : provider.get();
97   }
98 
isBound(Injector injector)99   public boolean isBound(Injector injector) {
100     return isBound(injector, getPrimaryBindingKey())
101         || isBound(injector, fixAnnotations(getPrimaryBindingKey()));
102   }
103 
isBound(Injector injector, Key<?> key)104   private boolean isBound(Injector injector, Key<?> key) {
105     // This method is particularly lame - we really need an API that can test
106     // for any binding, implicit or explicit
107     try {
108       return injector.getBinding(key) != null;
109     } catch (ConfigurationException e) {
110       return false;
111     }
112   }
113 
114   /**
115    * Replace annotation instances with annotation types, this is only
116    * appropriate for testing if a key is bound and not for injecting.
117    *
118    * See Guice bug 125,
119    * https://github.com/google/guice/issues/125
120    */
fixAnnotations(Key<?> key)121   public Key<?> fixAnnotations(Key<?> key) {
122     return key.getAnnotation() == null
123         ? key
124         : Key.get(key.getTypeLiteral(), key.getAnnotation().annotationType());
125   }
126 
getPrimaryBindingKey()127   Key<?> getPrimaryBindingKey() {
128     return isProvider
129         ? getBindingForType(getProvidedType(type))
130         : getBindingForType(type);
131   }
132 
getProvidedType(Type type)133   private Type getProvidedType(Type type) {
134     return ((ParameterizedType) type).getActualTypeArguments()[0];
135   }
136 
isProvider(Type type)137   private boolean isProvider(Type type) {
138     return type instanceof ParameterizedType
139         && ((ParameterizedType) type).getRawType() == Provider.class;
140   }
141 
getBindingForType(Type type)142   private Key<?> getBindingForType(Type type) {
143     return bindingAnnotation != null
144         ? Key.get(type, bindingAnnotation)
145         : Key.get(type);
146   }
147 
148   /**
149    * Returns the unique binding annotation from the specified list, or
150    * {@code null} if there are none.
151    *
152    * @throws IllegalStateException if multiple binding annotations exist.
153    */
getBindingAnnotation(Annotation[] annotations)154   private Annotation getBindingAnnotation(Annotation[] annotations) {
155     Annotation bindingAnnotation = null;
156     for (Annotation annotation : annotations) {
157       if (Annotations.isBindingAnnotation(annotation.annotationType())) {
158         checkArgument(bindingAnnotation == null,
159             "Parameter has multiple binding annotations: %s and %s", bindingAnnotation, annotation);
160         bindingAnnotation = annotation;
161       }
162     }
163     return bindingAnnotation;
164   }
165 }
166