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