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.spi; 18 19 import static com.google.inject.internal.MoreTypes.getRawType; 20 21 import com.google.common.collect.ImmutableList; 22 import com.google.common.collect.ImmutableSet; 23 import com.google.common.collect.Lists; 24 import com.google.inject.ConfigurationException; 25 import com.google.inject.Inject; 26 import com.google.inject.Key; 27 import com.google.inject.TypeLiteral; 28 import com.google.inject.internal.Annotations; 29 import com.google.inject.internal.Errors; 30 import com.google.inject.internal.ErrorsException; 31 import com.google.inject.internal.Nullability; 32 import com.google.inject.internal.util.Classes; 33 34 import java.lang.annotation.Annotation; 35 import java.lang.reflect.AnnotatedElement; 36 import java.lang.reflect.Constructor; 37 import java.lang.reflect.Field; 38 import java.lang.reflect.Member; 39 import java.lang.reflect.Method; 40 import java.lang.reflect.Modifier; 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.Collections; 44 import java.util.HashMap; 45 import java.util.Iterator; 46 import java.util.List; 47 import java.util.Map; 48 import java.util.Set; 49 import java.util.logging.Level; 50 import java.util.logging.Logger; 51 52 /** 53 * A constructor, field or method that can receive injections. Typically this is a member with the 54 * {@literal @}{@link Inject} annotation. For non-private, no argument constructors, the member may 55 * omit the annotation. 56 * 57 * @author crazybob@google.com (Bob Lee) 58 * @since 2.0 59 */ 60 public final class InjectionPoint { 61 62 private static final Logger logger = Logger.getLogger(InjectionPoint.class.getName()); 63 64 private final boolean optional; 65 private final Member member; 66 private final TypeLiteral<?> declaringType; 67 private final ImmutableList<Dependency<?>> dependencies; 68 InjectionPoint(TypeLiteral<?> declaringType, Method method, boolean optional)69 InjectionPoint(TypeLiteral<?> declaringType, Method method, boolean optional) { 70 this.member = method; 71 this.declaringType = declaringType; 72 this.optional = optional; 73 this.dependencies = forMember(method, declaringType, method.getParameterAnnotations()); 74 } 75 InjectionPoint(TypeLiteral<?> declaringType, Constructor<?> constructor)76 InjectionPoint(TypeLiteral<?> declaringType, Constructor<?> constructor) { 77 this.member = constructor; 78 this.declaringType = declaringType; 79 this.optional = false; 80 this.dependencies = forMember( 81 constructor, declaringType, constructor.getParameterAnnotations()); 82 } 83 InjectionPoint(TypeLiteral<?> declaringType, Field field, boolean optional)84 InjectionPoint(TypeLiteral<?> declaringType, Field field, boolean optional) { 85 this.member = field; 86 this.declaringType = declaringType; 87 this.optional = optional; 88 89 Annotation[] annotations = field.getAnnotations(); 90 91 Errors errors = new Errors(field); 92 Key<?> key = null; 93 try { 94 key = Annotations.getKey(declaringType.getFieldType(field), field, annotations, errors); 95 } catch (ConfigurationException e) { 96 errors.merge(e.getErrorMessages()); 97 } catch (ErrorsException e) { 98 errors.merge(e.getErrors()); 99 } 100 errors.throwConfigurationExceptionIfErrorsExist(); 101 102 this.dependencies = ImmutableList.<Dependency<?>>of( 103 newDependency(key, Nullability.allowsNull(annotations), -1)); 104 } 105 forMember(Member member, TypeLiteral<?> type, Annotation[][] paramterAnnotations)106 private ImmutableList<Dependency<?>> forMember(Member member, TypeLiteral<?> type, 107 Annotation[][] paramterAnnotations) { 108 Errors errors = new Errors(member); 109 Iterator<Annotation[]> annotationsIterator = Arrays.asList(paramterAnnotations).iterator(); 110 111 List<Dependency<?>> dependencies = Lists.newArrayList(); 112 int index = 0; 113 114 for (TypeLiteral<?> parameterType : type.getParameterTypes(member)) { 115 try { 116 Annotation[] parameterAnnotations = annotationsIterator.next(); 117 Key<?> key = Annotations.getKey(parameterType, member, parameterAnnotations, errors); 118 dependencies.add(newDependency(key, Nullability.allowsNull(parameterAnnotations), index)); 119 index++; 120 } catch (ConfigurationException e) { 121 errors.merge(e.getErrorMessages()); 122 } catch (ErrorsException e) { 123 errors.merge(e.getErrors()); 124 } 125 } 126 127 errors.throwConfigurationExceptionIfErrorsExist(); 128 return ImmutableList.copyOf(dependencies); 129 } 130 131 // This metohd is necessary to create a Dependency<T> with proper generic type information newDependency(Key<T> key, boolean allowsNull, int parameterIndex)132 private <T> Dependency<T> newDependency(Key<T> key, boolean allowsNull, int parameterIndex) { 133 return new Dependency<T>(this, key, allowsNull, parameterIndex); 134 } 135 136 /** 137 * Returns the injected constructor, field, or method. 138 */ getMember()139 public Member getMember() { 140 // TODO: Don't expose the original member (which probably has setAccessible(true)). 141 return member; 142 } 143 144 /** 145 * Returns the dependencies for this injection point. If the injection point is for a method or 146 * constructor, the dependencies will correspond to that member's parameters. Field injection 147 * points always have a single dependency for the field itself. 148 * 149 * @return a possibly-empty list 150 */ getDependencies()151 public List<Dependency<?>> getDependencies() { 152 return dependencies; 153 } 154 155 /** 156 * Returns true if this injection point shall be skipped if the injector cannot resolve bindings 157 * for all required dependencies. Both explicit bindings (as specified in a module), and implicit 158 * bindings ({@literal @}{@link com.google.inject.ImplementedBy ImplementedBy}, default 159 * constructors etc.) may be used to satisfy optional injection points. 160 */ isOptional()161 public boolean isOptional() { 162 return optional; 163 } 164 165 /** 166 * Returns true if the element is annotated with {@literal @}{@link Toolable}. 167 * 168 * @since 3.0 169 */ isToolable()170 public boolean isToolable() { 171 return ((AnnotatedElement)member).isAnnotationPresent(Toolable.class); 172 } 173 174 /** 175 * Returns the generic type that defines this injection point. If the member exists on a 176 * parameterized type, the result will include more type information than the member's {@link 177 * Member#getDeclaringClass() raw declaring class}. 178 * 179 * @since 3.0 180 */ getDeclaringType()181 public TypeLiteral<?> getDeclaringType() { 182 return declaringType; 183 } 184 equals(Object o)185 @Override public boolean equals(Object o) { 186 return o instanceof InjectionPoint 187 && member.equals(((InjectionPoint) o).member) 188 && declaringType.equals(((InjectionPoint) o).declaringType); 189 } 190 hashCode()191 @Override public int hashCode() { 192 return member.hashCode() ^ declaringType.hashCode(); 193 } 194 toString()195 @Override public String toString() { 196 return Classes.toString(member); 197 } 198 199 /** 200 * Returns a new injection point for the specified constructor. If the declaring type of {@code 201 * constructor} is parameterized (such as {@code List<T>}), prefer the overload that includes a 202 * type literal. 203 * 204 * @param constructor any single constructor present on {@code type}. 205 * 206 * @since 3.0 207 */ forConstructor(Constructor<T> constructor)208 public static <T> InjectionPoint forConstructor(Constructor<T> constructor) { 209 return new InjectionPoint(TypeLiteral.get(constructor.getDeclaringClass()), constructor); 210 } 211 212 /** 213 * Returns a new injection point for the specified constructor of {@code type}. 214 * 215 * @param constructor any single constructor present on {@code type}. 216 * @param type the concrete type that defines {@code constructor}. 217 * 218 * @since 3.0 219 */ forConstructor( Constructor<T> constructor, TypeLiteral<? extends T> type)220 public static <T> InjectionPoint forConstructor( 221 Constructor<T> constructor, TypeLiteral<? extends T> type) { 222 if (type.getRawType() != constructor.getDeclaringClass()) { 223 new Errors(type) 224 .constructorNotDefinedByType(constructor, type) 225 .throwConfigurationExceptionIfErrorsExist(); 226 } 227 228 return new InjectionPoint(type, constructor); 229 } 230 231 /** 232 * Returns a new injection point for the injectable constructor of {@code type}. 233 * 234 * @param type a concrete type with exactly one constructor annotated {@literal @}{@link Inject}, 235 * or a no-arguments constructor that is not private. 236 * @throws ConfigurationException if there is no injectable constructor, more than one injectable 237 * constructor, or if parameters of the injectable constructor are malformed, such as a 238 * parameter with multiple binding annotations. 239 */ forConstructorOf(TypeLiteral<?> type)240 public static InjectionPoint forConstructorOf(TypeLiteral<?> type) { 241 Class<?> rawType = getRawType(type.getType()); 242 Errors errors = new Errors(rawType); 243 244 Constructor<?> injectableConstructor = null; 245 for (Constructor<?> constructor : rawType.getDeclaredConstructors()) { 246 247 boolean optional; 248 Inject guiceInject = constructor.getAnnotation(Inject.class); 249 if (guiceInject == null) { 250 javax.inject.Inject javaxInject = constructor.getAnnotation(javax.inject.Inject.class); 251 if (javaxInject == null) { 252 continue; 253 } 254 optional = false; 255 } else { 256 optional = guiceInject.optional(); 257 } 258 259 if (optional) { 260 errors.optionalConstructor(constructor); 261 } 262 263 if (injectableConstructor != null) { 264 errors.tooManyConstructors(rawType); 265 } 266 267 injectableConstructor = constructor; 268 checkForMisplacedBindingAnnotations(injectableConstructor, errors); 269 } 270 271 errors.throwConfigurationExceptionIfErrorsExist(); 272 273 if (injectableConstructor != null) { 274 return new InjectionPoint(type, injectableConstructor); 275 } 276 277 // If no annotated constructor is found, look for a no-arg constructor instead. 278 try { 279 Constructor<?> noArgConstructor = rawType.getDeclaredConstructor(); 280 281 // Disallow private constructors on non-private classes (unless they have @Inject) 282 if (Modifier.isPrivate(noArgConstructor.getModifiers()) 283 && !Modifier.isPrivate(rawType.getModifiers())) { 284 errors.missingConstructor(rawType); 285 throw new ConfigurationException(errors.getMessages()); 286 } 287 288 checkForMisplacedBindingAnnotations(noArgConstructor, errors); 289 return new InjectionPoint(type, noArgConstructor); 290 } catch (NoSuchMethodException e) { 291 errors.missingConstructor(rawType); 292 throw new ConfigurationException(errors.getMessages()); 293 } 294 } 295 296 /** 297 * Returns a new injection point for the injectable constructor of {@code type}. 298 * 299 * @param type a concrete type with exactly one constructor annotated {@literal @}{@link Inject}, 300 * or a no-arguments constructor that is not private. 301 * @throws ConfigurationException if there is no injectable constructor, more than one injectable 302 * constructor, or if parameters of the injectable constructor are malformed, such as a 303 * parameter with multiple binding annotations. 304 */ forConstructorOf(Class<?> type)305 public static InjectionPoint forConstructorOf(Class<?> type) { 306 return forConstructorOf(TypeLiteral.get(type)); 307 } 308 309 /** 310 * Returns a new injection point for the specified method of {@code type}. 311 * This is useful for extensions that need to build dependency graphs from 312 * arbitrary methods. 313 * 314 * @param method any single method present on {@code type}. 315 * @param type the concrete type that defines {@code method}. 316 * 317 * @since 4.0 318 */ forMethod(Method method, TypeLiteral<T> type)319 public static <T> InjectionPoint forMethod(Method method, TypeLiteral<T> type) { 320 return new InjectionPoint(type, method, false); 321 } 322 323 /** 324 * Returns all static method and field injection points on {@code type}. 325 * 326 * @return a possibly empty set of injection points. The set has a specified iteration order. All 327 * fields are returned and then all methods. Within the fields, supertype fields are returned 328 * before subtype fields. Similarly, supertype methods are returned before subtype methods. 329 * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as 330 * a field with multiple binding annotations. The exception's {@link 331 * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} 332 * of the valid injection points. 333 */ forStaticMethodsAndFields(TypeLiteral<?> type)334 public static Set<InjectionPoint> forStaticMethodsAndFields(TypeLiteral<?> type) { 335 Errors errors = new Errors(); 336 337 Set<InjectionPoint> result; 338 339 if (type.getRawType().isInterface()) { 340 errors.staticInjectionOnInterface(type.getRawType()); 341 result = null; 342 } else { 343 result = getInjectionPoints(type, true, errors); 344 } 345 346 if (errors.hasErrors()) { 347 throw new ConfigurationException(errors.getMessages()).withPartialValue(result); 348 } 349 return result; 350 } 351 352 /** 353 * Returns all static method and field injection points on {@code type}. 354 * 355 * @return a possibly empty set of injection points. The set has a specified iteration order. All 356 * fields are returned and then all methods. Within the fields, supertype fields are returned 357 * before subtype fields. Similarly, supertype methods are returned before subtype methods. 358 * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as 359 * a field with multiple binding annotations. The exception's {@link 360 * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} 361 * of the valid injection points. 362 */ forStaticMethodsAndFields(Class<?> type)363 public static Set<InjectionPoint> forStaticMethodsAndFields(Class<?> type) { 364 return forStaticMethodsAndFields(TypeLiteral.get(type)); 365 } 366 367 /** 368 * Returns all instance method and field injection points on {@code type}. 369 * 370 * @return a possibly empty set of injection points. The set has a specified iteration order. All 371 * fields are returned and then all methods. Within the fields, supertype fields are returned 372 * before subtype fields. Similarly, supertype methods are returned before subtype methods. 373 * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as 374 * a field with multiple binding annotations. The exception's {@link 375 * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} 376 * of the valid injection points. 377 */ forInstanceMethodsAndFields(TypeLiteral<?> type)378 public static Set<InjectionPoint> forInstanceMethodsAndFields(TypeLiteral<?> type) { 379 Errors errors = new Errors(); 380 Set<InjectionPoint> result = getInjectionPoints(type, false, errors); 381 if (errors.hasErrors()) { 382 throw new ConfigurationException(errors.getMessages()).withPartialValue(result); 383 } 384 return result; 385 } 386 387 /** 388 * Returns all instance method and field injection points on {@code type}. 389 * 390 * @return a possibly empty set of injection points. The set has a specified iteration order. All 391 * fields are returned and then all methods. Within the fields, supertype fields are returned 392 * before subtype fields. Similarly, supertype methods are returned before subtype methods. 393 * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as 394 * a field with multiple binding annotations. The exception's {@link 395 * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} 396 * of the valid injection points. 397 */ forInstanceMethodsAndFields(Class<?> type)398 public static Set<InjectionPoint> forInstanceMethodsAndFields(Class<?> type) { 399 return forInstanceMethodsAndFields(TypeLiteral.get(type)); 400 } 401 402 /** 403 * Returns true if the binding annotation is in the wrong place. 404 */ checkForMisplacedBindingAnnotations(Member member, Errors errors)405 private static boolean checkForMisplacedBindingAnnotations(Member member, Errors errors) { 406 Annotation misplacedBindingAnnotation = Annotations.findBindingAnnotation( 407 errors, member, ((AnnotatedElement) member).getAnnotations()); 408 if (misplacedBindingAnnotation == null) { 409 return false; 410 } 411 412 // don't warn about misplaced binding annotations on methods when there's a field with the same 413 // name. In Scala, fields always get accessor methods (that we need to ignore). See bug 242. 414 if (member instanceof Method) { 415 try { 416 if (member.getDeclaringClass().getDeclaredField(member.getName()) != null) { 417 return false; 418 } 419 } catch (NoSuchFieldException ignore) { 420 } 421 } 422 423 errors.misplacedBindingAnnotation(member, misplacedBindingAnnotation); 424 return true; 425 } 426 427 /** 428 * Node in the doubly-linked list of injectable members (fields and methods). 429 */ 430 static abstract class InjectableMember { 431 final TypeLiteral<?> declaringType; 432 final boolean optional; 433 final boolean jsr330; 434 InjectableMember previous; 435 InjectableMember next; 436 InjectableMember(TypeLiteral<?> declaringType, Annotation atInject)437 InjectableMember(TypeLiteral<?> declaringType, Annotation atInject) { 438 this.declaringType = declaringType; 439 440 if (atInject.annotationType() == javax.inject.Inject.class) { 441 optional = false; 442 jsr330 = true; 443 return; 444 } 445 446 jsr330 = false; 447 optional = ((Inject) atInject).optional(); 448 } 449 toInjectionPoint()450 abstract InjectionPoint toInjectionPoint(); 451 } 452 453 static class InjectableField extends InjectableMember { 454 final Field field; InjectableField(TypeLiteral<?> declaringType, Field field, Annotation atInject)455 InjectableField(TypeLiteral<?> declaringType, Field field, 456 Annotation atInject) { 457 super(declaringType, atInject); 458 this.field = field; 459 } 460 461 @Override toInjectionPoint()462 InjectionPoint toInjectionPoint() { 463 return new InjectionPoint(declaringType, field, optional); 464 } 465 } 466 467 static class InjectableMethod extends InjectableMember { 468 final Method method; 469 /** 470 * true if this method overrode a method that was annotated 471 * with com.google.inject.Inject. used to allow different 472 * override behavior for guice inject vs javax.inject.Inject 473 */ 474 boolean overrodeGuiceInject; InjectableMethod(TypeLiteral<?> declaringType, Method method, Annotation atInject)475 InjectableMethod(TypeLiteral<?> declaringType, Method method, 476 Annotation atInject) { 477 super(declaringType, atInject); 478 this.method = method; 479 } 480 481 @Override toInjectionPoint()482 InjectionPoint toInjectionPoint() { 483 return new InjectionPoint(declaringType, method, optional); 484 } 485 isFinal()486 public boolean isFinal() { 487 return Modifier.isFinal(method.getModifiers()); 488 } 489 } 490 getAtInject(AnnotatedElement member)491 static Annotation getAtInject(AnnotatedElement member) { 492 Annotation a = member.getAnnotation(javax.inject.Inject.class); 493 return a == null ? member.getAnnotation(Inject.class) : a; 494 } 495 496 /** 497 * Linked list of injectable members. 498 */ 499 static class InjectableMembers { 500 InjectableMember head; 501 InjectableMember tail; 502 add(InjectableMember member)503 void add(InjectableMember member) { 504 if (head == null) { 505 head = tail = member; 506 } else { 507 member.previous = tail; 508 tail.next = member; 509 tail = member; 510 } 511 } 512 remove(InjectableMember member)513 void remove(InjectableMember member) { 514 if (member.previous != null) { 515 member.previous.next = member.next; 516 } 517 if (member.next != null) { 518 member.next.previous = member.previous; 519 } 520 if (head == member) { 521 head = member.next; 522 } 523 if (tail == member) { 524 tail = member.previous; 525 } 526 } 527 isEmpty()528 boolean isEmpty() { 529 return head == null; 530 } 531 } 532 533 /** Position in type hierarchy. */ 534 enum Position { 535 TOP, // No need to check for overridden methods 536 MIDDLE, 537 BOTTOM // Methods won't be overridden 538 } 539 540 /** 541 * Keeps track of injectable methods so we can remove methods that get overridden in O(1) time. 542 * Uses our position in the type hierarchy to perform optimizations. 543 */ 544 static class OverrideIndex { 545 final InjectableMembers injectableMembers; 546 Map<Signature, List<InjectableMethod>> bySignature; 547 Position position = Position.TOP; 548 OverrideIndex(InjectableMembers injectableMembers)549 OverrideIndex(InjectableMembers injectableMembers) { 550 this.injectableMembers = injectableMembers; 551 } 552 553 /* Caches the signature for the last method. */ 554 Method lastMethod; 555 Signature lastSignature; 556 557 /** 558 * Removes a method overridden by the given method, if present. In order to 559 * remain backwards compatible with prior Guice versions, this will *not* 560 * remove overridden methods if 'alwaysRemove' is false and the overridden 561 * signature was annotated with a com.google.inject.Inject. 562 * 563 * @param method 564 * The method used to determine what is overridden and should be 565 * removed. 566 * @param alwaysRemove 567 * true if overridden methods should be removed even if they were 568 * guice @Inject 569 * @param injectableMethod 570 * if this method overrode any guice @Inject methods, 571 * {@link InjectableMethod#overrodeGuiceInject} is set to true 572 */ removeIfOverriddenBy(Method method, boolean alwaysRemove, InjectableMethod injectableMethod)573 boolean removeIfOverriddenBy(Method method, boolean alwaysRemove, 574 InjectableMethod injectableMethod) { 575 if (position == Position.TOP) { 576 // If we're at the top of the hierarchy, there's nothing to override. 577 return false; 578 } 579 580 if (bySignature == null) { 581 // We encountered a method in a subclass. Time to index the 582 // methods in the parent class. 583 bySignature = new HashMap<Signature, List<InjectableMethod>>(); 584 for (InjectableMember member = injectableMembers.head; member != null; 585 member = member.next) { 586 if (!(member instanceof InjectableMethod)) continue; 587 InjectableMethod im = (InjectableMethod) member; 588 if (im.isFinal()) continue; 589 List<InjectableMethod> methods = new ArrayList<InjectableMethod>(); 590 methods.add(im); 591 bySignature.put(new Signature(im.method), methods); 592 } 593 } 594 595 lastMethod = method; 596 Signature signature = lastSignature = new Signature(method); 597 List<InjectableMethod> methods = bySignature.get(signature); 598 boolean removed = false; 599 if (methods != null) { 600 for (Iterator<InjectableMethod> iterator = methods.iterator(); 601 iterator.hasNext();) { 602 InjectableMethod possiblyOverridden = iterator.next(); 603 if (overrides(method, possiblyOverridden.method)) { 604 boolean wasGuiceInject = 605 !possiblyOverridden.jsr330 || possiblyOverridden.overrodeGuiceInject; 606 if(injectableMethod != null) { 607 injectableMethod.overrodeGuiceInject = wasGuiceInject; 608 } 609 // Only actually remove the methods if we want to force 610 // remove or if the signature never specified @com.google.inject.Inject 611 // somewhere. 612 if(alwaysRemove || !wasGuiceInject) { 613 removed = true; 614 iterator.remove(); 615 injectableMembers.remove(possiblyOverridden); 616 } 617 } 618 } 619 } 620 return removed; 621 } 622 623 /** 624 * Adds the given method to the list of injection points. Keeps track of it in this index 625 * in case it gets overridden. 626 */ add(InjectableMethod injectableMethod)627 void add(InjectableMethod injectableMethod) { 628 injectableMembers.add(injectableMethod); 629 if (position == Position.BOTTOM 630 || injectableMethod.isFinal()) { 631 // This method can't be overridden, so there's no need to index it. 632 return; 633 } 634 if (bySignature != null) { 635 // Try to reuse the signature we created during removal 636 Signature signature = injectableMethod.method == lastMethod 637 ? lastSignature : new Signature(injectableMethod.method); 638 List<InjectableMethod> methods = bySignature.get(signature); 639 if (methods == null) { 640 methods = new ArrayList<InjectableMethod>(); 641 bySignature.put(signature, methods); 642 } 643 methods.add(injectableMethod); 644 } 645 } 646 } 647 648 /** 649 * Returns an ordered, immutable set of injection points for the given type. Members in 650 * superclasses come before members in subclasses. Within a class, fields come before methods. 651 * Overridden methods are filtered out. 652 * 653 * @param statics true is this method should return static members, false for instance members 654 * @param errors used to record errors 655 */ getInjectionPoints(final TypeLiteral<?> type, boolean statics, Errors errors)656 private static Set<InjectionPoint> getInjectionPoints(final TypeLiteral<?> type, 657 boolean statics, Errors errors) { 658 InjectableMembers injectableMembers = new InjectableMembers(); 659 OverrideIndex overrideIndex = null; 660 661 List<TypeLiteral<?>> hierarchy = hierarchyFor(type); 662 int topIndex = hierarchy.size() - 1; 663 for (int i = topIndex; i >= 0; i--) { 664 if (overrideIndex != null && i < topIndex) { 665 // Knowing the position within the hierarchy helps us make optimizations. 666 if (i == 0) { 667 overrideIndex.position = Position.BOTTOM; 668 } else { 669 overrideIndex.position = Position.MIDDLE; 670 } 671 } 672 673 TypeLiteral<?> current = hierarchy.get(i); 674 675 for (Field field : current.getRawType().getDeclaredFields()) { 676 if (Modifier.isStatic(field.getModifiers()) == statics) { 677 Annotation atInject = getAtInject(field); 678 if (atInject != null) { 679 InjectableField injectableField = new InjectableField(current, field, atInject); 680 if (injectableField.jsr330 && Modifier.isFinal(field.getModifiers())) { 681 errors.cannotInjectFinalField(field); 682 } 683 injectableMembers.add(injectableField); 684 } 685 } 686 } 687 688 for (Method method : current.getRawType().getDeclaredMethods()) { 689 if (isEligibleForInjection(method, statics)) { 690 Annotation atInject = getAtInject(method); 691 if (atInject != null) { 692 InjectableMethod injectableMethod = new InjectableMethod( 693 current, method, atInject); 694 if (checkForMisplacedBindingAnnotations(method, errors) 695 || !isValidMethod(injectableMethod, errors)) { 696 if (overrideIndex != null) { 697 boolean removed = overrideIndex.removeIfOverriddenBy(method, false, injectableMethod); 698 if(removed) { 699 logger.log(Level.WARNING, "Method: {0} is not a valid injectable method (" 700 + "because it either has misplaced binding annotations " 701 + "or specifies type parameters) but is overriding a method that is valid. " 702 + "Because it is not valid, the method will not be injected. " 703 + "To fix this, make the method a valid injectable method.", method); 704 } 705 } 706 continue; 707 } 708 if (statics) { 709 injectableMembers.add(injectableMethod); 710 } else { 711 if (overrideIndex == null) { 712 /* 713 * Creating the override index lazily means that the first type in the hierarchy 714 * with injectable methods (not necessarily the top most type) will be treated as 715 * the TOP position and will enjoy the same optimizations (no checks for overridden 716 * methods, etc.). 717 */ 718 overrideIndex = new OverrideIndex(injectableMembers); 719 } else { 720 // Forcibly remove the overriden method, otherwise we'll inject 721 // it twice. 722 overrideIndex.removeIfOverriddenBy(method, true, injectableMethod); 723 } 724 overrideIndex.add(injectableMethod); 725 } 726 } else { 727 if(overrideIndex != null) { 728 boolean removed = overrideIndex.removeIfOverriddenBy(method, false, null); 729 if(removed) { 730 logger.log(Level.WARNING, "Method: {0} is not annotated with @Inject but " 731 + "is overriding a method that is annotated with @javax.inject.Inject. Because " 732 + "it is not annotated with @Inject, the method will not be injected. " 733 + "To fix this, annotate the method with @Inject.", method); 734 } 735 } 736 } 737 } 738 } 739 } 740 741 if (injectableMembers.isEmpty()) { 742 return Collections.emptySet(); 743 } 744 745 ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder(); 746 for (InjectableMember im = injectableMembers.head; im != null; 747 im = im.next) { 748 try { 749 builder.add(im.toInjectionPoint()); 750 } catch (ConfigurationException ignorable) { 751 if (!im.optional) { 752 errors.merge(ignorable.getErrorMessages()); 753 } 754 } 755 } 756 return builder.build(); 757 } 758 759 /** 760 * Returns true if the method is eligible to be injected. This is different than 761 * {@link #isValidMethod}, because ineligibility will not drop a method 762 * from being injected if a superclass was eligible & valid. 763 * Bridge & synthetic methods are excluded from eligibility for two reasons: 764 * 765 * <p>Prior to Java8, javac would generate these methods in subclasses without 766 * annotations, which means this would accidentally stop injecting a method 767 * annotated with {@link javax.inject.Inject}, since the spec says to stop 768 * injecting if a subclass isn't annotated with it. 769 * 770 * <p>Starting at Java8, javac copies the annotations to the generated subclass 771 * method, except it leaves out the generic types. If this considered it a valid 772 * injectable method, this would eject the parent's overridden method that had the 773 * proper generic types, and would use invalid injectable parameters as a result. 774 * 775 * <p>The fix for both is simply to ignore these synthetic bridge methods. 776 */ isEligibleForInjection(Method method, boolean statics)777 private static boolean isEligibleForInjection(Method method, boolean statics) { 778 return Modifier.isStatic(method.getModifiers()) == statics 779 && !method.isBridge() 780 && !method.isSynthetic(); 781 } 782 isValidMethod(InjectableMethod injectableMethod, Errors errors)783 private static boolean isValidMethod(InjectableMethod injectableMethod, 784 Errors errors) { 785 boolean result = true; 786 if (injectableMethod.jsr330) { 787 Method method = injectableMethod.method; 788 if (Modifier.isAbstract(method.getModifiers())) { 789 errors.cannotInjectAbstractMethod(method); 790 result = false; 791 } 792 if (method.getTypeParameters().length > 0) { 793 errors.cannotInjectMethodWithTypeParameters(method); 794 result = false; 795 } 796 } 797 return result; 798 } 799 hierarchyFor(TypeLiteral<?> type)800 private static List<TypeLiteral<?>> hierarchyFor(TypeLiteral<?> type) { 801 List<TypeLiteral<?>> hierarchy = new ArrayList<TypeLiteral<?>>(); 802 TypeLiteral<?> current = type; 803 while (current.getRawType() != Object.class) { 804 hierarchy.add(current); 805 current = current.getSupertype(current.getRawType().getSuperclass()); 806 } 807 return hierarchy; 808 } 809 810 /** 811 * Returns true if a overrides b. Assumes signatures of a and b are the same and a's declaring 812 * class is a subclass of b's declaring class. 813 */ overrides(Method a, Method b)814 private static boolean overrides(Method a, Method b) { 815 // See JLS section 8.4.8.1 816 int modifiers = b.getModifiers(); 817 if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) { 818 return true; 819 } 820 if (Modifier.isPrivate(modifiers)) { 821 return false; 822 } 823 // b must be package-private 824 return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage()); 825 } 826 827 /** 828 * A method signature. Used to handle method overridding. 829 */ 830 static class Signature { 831 832 final String name; 833 final Class[] parameterTypes; 834 final int hash; 835 Signature(Method method)836 Signature(Method method) { 837 this.name = method.getName(); 838 this.parameterTypes = method.getParameterTypes(); 839 840 int h = name.hashCode(); 841 h = h * 31 + parameterTypes.length; 842 for (Class parameterType : parameterTypes) { 843 h = h * 31 + parameterType.hashCode(); 844 } 845 this.hash = h; 846 } 847 hashCode()848 @Override public int hashCode() { 849 return this.hash; 850 } 851 equals(Object o)852 @Override public boolean equals(Object o) { 853 if (!(o instanceof Signature)) { 854 return false; 855 } 856 857 Signature other = (Signature) o; 858 if (!name.equals(other.name)) { 859 return false; 860 } 861 862 if (parameterTypes.length != other.parameterTypes.length) { 863 return false; 864 } 865 866 for (int i = 0; i < parameterTypes.length; i++) { 867 if (parameterTypes[i] != other.parameterTypes[i]) { 868 return false; 869 } 870 } 871 872 return true; 873 } 874 } 875 } 876