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