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