1 /* 2 * Copyright (C) 2008 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.internal; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.common.collect.HashMultimap; 22 import com.google.common.collect.ImmutableList; 23 import com.google.common.collect.ImmutableSet; 24 import com.google.common.collect.Lists; 25 import com.google.common.collect.Multimap; 26 import com.google.inject.Binder; 27 import com.google.inject.Key; 28 import com.google.inject.Module; 29 import com.google.inject.Provides; 30 import com.google.inject.TypeLiteral; 31 import com.google.inject.spi.InjectionPoint; 32 import com.google.inject.spi.Message; 33 import com.google.inject.spi.ModuleAnnotatedMethodScanner; 34 import com.google.inject.util.Modules; 35 import java.lang.annotation.Annotation; 36 import java.lang.reflect.Member; 37 import java.lang.reflect.Method; 38 import java.lang.reflect.Modifier; 39 import java.util.Arrays; 40 import java.util.List; 41 42 /** 43 * Creates bindings to methods annotated with {@literal @}{@link Provides}. Use the scope and 44 * binding annotations on the provider method to configure the binding. 45 * 46 * @author crazybob@google.com (Bob Lee) 47 * @author jessewilson@google.com (Jesse Wilson) 48 */ 49 public final class ProviderMethodsModule implements Module { 50 private final Object delegate; 51 private final TypeLiteral<?> typeLiteral; 52 private final boolean skipFastClassGeneration; 53 private final ModuleAnnotatedMethodScanner scanner; 54 ProviderMethodsModule( Object delegate, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner)55 private ProviderMethodsModule( 56 Object delegate, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner) { 57 this.delegate = checkNotNull(delegate, "delegate"); 58 this.typeLiteral = TypeLiteral.get(this.delegate.getClass()); 59 this.skipFastClassGeneration = skipFastClassGeneration; 60 this.scanner = scanner; 61 } 62 63 /** Returns a module which creates bindings for provider methods from the given module. */ forModule(Module module)64 public static Module forModule(Module module) { 65 return forObject(module, false, ProvidesMethodScanner.INSTANCE); 66 } 67 68 /** Returns a module which creates bindings methods in the module that match the scanner. */ forModule(Object module, ModuleAnnotatedMethodScanner scanner)69 public static Module forModule(Object module, ModuleAnnotatedMethodScanner scanner) { 70 return forObject(module, false, scanner); 71 } 72 73 /** 74 * Returns a module which creates bindings for provider methods from the given object. This is 75 * useful notably for <a href="http://code.google.com/p/google-gin/">GIN</a> 76 * 77 * <p>This will skip bytecode generation for provider methods, since it is assumed that callers 78 * are only interested in Module metadata. 79 */ forObject(Object object)80 public static Module forObject(Object object) { 81 return forObject(object, true, ProvidesMethodScanner.INSTANCE); 82 } 83 forObject( Object object, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner)84 private static Module forObject( 85 Object object, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner) { 86 // avoid infinite recursion, since installing a module always installs itself 87 if (object instanceof ProviderMethodsModule) { 88 return Modules.EMPTY_MODULE; 89 } 90 91 return new ProviderMethodsModule(object, skipFastClassGeneration, scanner); 92 } 93 getDelegateModule()94 public Object getDelegateModule() { 95 return delegate; 96 } 97 98 @Override configure(Binder binder)99 public void configure(Binder binder) { 100 for (ProviderMethod<?> providerMethod : getProviderMethods(binder)) { 101 providerMethod.configure(binder); 102 } 103 } 104 getProviderMethods(Binder binder)105 public List<ProviderMethod<?>> getProviderMethods(Binder binder) { 106 List<ProviderMethod<?>> result = null; 107 // The highest class in the type hierarchy that contained a provider method definition. 108 Class<?> superMostClass = delegate.getClass(); 109 for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) { 110 for (Method method : c.getDeclaredMethods()) { 111 Annotation annotation = getAnnotation(binder, method); 112 if (annotation != null) { 113 if (result == null) { 114 result = Lists.newArrayList(); 115 } 116 result.add(createProviderMethod(binder, method, annotation)); 117 superMostClass = c; 118 } 119 } 120 } 121 if (result == null) { 122 // We didn't find anything 123 return ImmutableList.of(); 124 } 125 // We have found some provider methods, now we need to check if any were overridden. 126 // We do this as a separate pass to avoid calculating all the signatures when there are no 127 // provides methods, or when all provides methods are defined in a single class. 128 Multimap<Signature, Method> methodsBySignature = null; 129 // We can stop scanning when we see superMostClass, since no superclass method can override 130 // a method in a subclass. Corrollary, if superMostClass == delegate.getClass(), there can be 131 // no overrides of a provides method. 132 for (Class<?> c = delegate.getClass(); c != superMostClass; c = c.getSuperclass()) { 133 for (Method method : c.getDeclaredMethods()) { 134 if (((method.getModifiers() & (Modifier.PRIVATE | Modifier.STATIC)) == 0) 135 && !method.isBridge() 136 && !method.isSynthetic()) { 137 if (methodsBySignature == null) { 138 methodsBySignature = HashMultimap.create(); 139 } 140 methodsBySignature.put(new Signature(typeLiteral, method), method); 141 } 142 } 143 } 144 if (methodsBySignature != null) { 145 // we have found all the signatures and now need to identify if any were overridden 146 // In the worst case this will have O(n^2) in the number of @Provides methods, but that is 147 // only assuming that every method is an override, in general it should be very quick. 148 for (ProviderMethod<?> provider : result) { 149 Method method = provider.getMethod(); 150 for (Method matchingSignature : 151 methodsBySignature.get(new Signature(typeLiteral, method))) { 152 // matching signature is in the same class or a super class, therefore method cannot be 153 // overridding it. 154 if (matchingSignature.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) { 155 continue; 156 } 157 // now we know matching signature is in a subtype of method.getDeclaringClass() 158 if (overrides(matchingSignature, method)) { 159 String annotationString = 160 provider.getAnnotation().annotationType() == Provides.class 161 ? "@Provides" 162 : "@" + provider.getAnnotation().annotationType().getCanonicalName(); 163 binder.addError( 164 "Overriding " 165 + annotationString 166 + " methods is not allowed." 167 + "\n\t" 168 + annotationString 169 + " method: %s\n\toverridden by: %s", 170 method, 171 matchingSignature); 172 break; 173 } 174 } 175 } 176 } 177 return result; 178 } 179 180 /** Returns the annotation that is claimed by the scanner, or null if there is none. */ getAnnotation(Binder binder, Method method)181 private Annotation getAnnotation(Binder binder, Method method) { 182 if (method.isBridge() || method.isSynthetic()) { 183 return null; 184 } 185 Annotation annotation = null; 186 for (Class<? extends Annotation> annotationClass : scanner.annotationClasses()) { 187 Annotation foundAnnotation = method.getAnnotation(annotationClass); 188 if (foundAnnotation != null) { 189 if (annotation != null) { 190 binder.addError( 191 "More than one annotation claimed by %s on method %s." 192 + " Methods can only have one annotation claimed per scanner.", 193 scanner, method); 194 return null; 195 } 196 annotation = foundAnnotation; 197 } 198 } 199 return annotation; 200 } 201 202 private static final class Signature { 203 final Class<?>[] parameters; 204 final String name; 205 final int hashCode; 206 Signature(TypeLiteral<?> typeLiteral, Method method)207 Signature(TypeLiteral<?> typeLiteral, Method method) { 208 this.name = method.getName(); 209 // We need to 'resolve' the parameters against the actual class type in case this method uses 210 // type parameters. This is so we can detect overrides of generic superclass methods where 211 // the subclass specifies the type parameter. javac implements these kinds of overrides via 212 // bridge methods, but we don't want to give errors on bridge methods (but rather the target 213 // of the bridge). 214 List<TypeLiteral<?>> resolvedParameterTypes = typeLiteral.getParameterTypes(method); 215 this.parameters = new Class<?>[resolvedParameterTypes.size()]; 216 int i = 0; 217 for (TypeLiteral<?> type : resolvedParameterTypes) { 218 parameters[i] = type.getRawType(); 219 } 220 this.hashCode = name.hashCode() + 31 * Arrays.hashCode(parameters); 221 } 222 223 @Override equals(Object obj)224 public boolean equals(Object obj) { 225 if (obj instanceof Signature) { 226 Signature other = (Signature) obj; 227 return other.name.equals(name) && Arrays.equals(parameters, other.parameters); 228 } 229 return false; 230 } 231 232 @Override hashCode()233 public int hashCode() { 234 return hashCode; 235 } 236 } 237 238 /** Returns true if a overrides b, assumes that the signatures match */ overrides(Method a, Method b)239 private static boolean overrides(Method a, Method b) { 240 // See JLS section 8.4.8.1 241 int modifiers = b.getModifiers(); 242 if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) { 243 return true; 244 } 245 if (Modifier.isPrivate(modifiers)) { 246 return false; 247 } 248 // b must be package-private 249 return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage()); 250 } 251 createProviderMethod( Binder binder, Method method, Annotation annotation)252 private <T> ProviderMethod<T> createProviderMethod( 253 Binder binder, Method method, Annotation annotation) { 254 binder = binder.withSource(method); 255 Errors errors = new Errors(method); 256 257 // prepare the parameter providers 258 InjectionPoint point = InjectionPoint.forMethod(method, typeLiteral); 259 @SuppressWarnings("unchecked") // Define T as the method's return type. 260 TypeLiteral<T> returnType = (TypeLiteral<T>) typeLiteral.getReturnType(method); 261 Key<T> key = getKey(errors, returnType, method, method.getAnnotations()); 262 try { 263 key = scanner.prepareMethod(binder, annotation, key, point); 264 } catch (Throwable t) { 265 binder.addError(t); 266 } 267 Class<? extends Annotation> scopeAnnotation = 268 Annotations.findScopeAnnotation(errors, method.getAnnotations()); 269 for (Message message : errors.getMessages()) { 270 binder.addError(message); 271 } 272 return ProviderMethod.create( 273 key, 274 method, 275 delegate, 276 ImmutableSet.copyOf(point.getDependencies()), 277 scopeAnnotation, 278 skipFastClassGeneration, 279 annotation); 280 } 281 getKey(Errors errors, TypeLiteral<T> type, Member member, Annotation[] annotations)282 <T> Key<T> getKey(Errors errors, TypeLiteral<T> type, Member member, Annotation[] annotations) { 283 Annotation bindingAnnotation = Annotations.findBindingAnnotation(errors, member, annotations); 284 return bindingAnnotation == null ? Key.get(type) : Key.get(type, bindingAnnotation); 285 } 286 287 @Override equals(Object o)288 public boolean equals(Object o) { 289 return o instanceof ProviderMethodsModule 290 && ((ProviderMethodsModule) o).delegate == delegate 291 && ((ProviderMethodsModule) o).scanner == scanner; 292 } 293 294 @Override hashCode()295 public int hashCode() { 296 return delegate.hashCode(); 297 } 298 } 299