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