/** * There are some nasty bugs for introspection with generics. This method addresses those nasty * bugs and tries to find proper methods if available * http://bugs.sun.com/view_bug.do?bug_id=6788525 http://bugs.sun.com/view_bug.do?bug_id=6528714 * * @param descriptor * @return */ private static PropertyDescriptor fixGenericDescriptor( Class<?> clazz, PropertyDescriptor descriptor) { Method readMethod = descriptor.getReadMethod(); Method writeMethod = descriptor.getWriteMethod(); if (readMethod != null && (readMethod.isBridge() || readMethod.isSynthetic())) { String propertyName = descriptor.getName(); // capitalize the first letter of the string; String baseName = Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); String setMethodName = "set" + baseName; String getMethodName = "get" + baseName; Method[] methods = clazz.getMethods(); for (Method method : methods) { if (method.getName().equals(getMethodName) && !method.isBridge() && !method.isSynthetic()) { try { descriptor.setReadMethod(method); } catch (IntrospectionException e) { // move on } } if (method.getName().equals(setMethodName) && !method.isBridge() && !method.isSynthetic()) { try { descriptor.setWriteMethod(method); } catch (IntrospectionException e) { // move on } } } } return descriptor; }
/** * Test case for TEATROVE-55. * * <p>https://github.com/teatrove/teatrove/issues/55 */ @Test public void testGetConstructorWithGenerics() throws Exception { ClassInjector injector = ClassInjector.getInstance(this.getClass().getClassLoader()); // build first constructor that purely merges general play context Constructor<?> ctor1 = MergedClass.getConstructor2( injector, new Class[] {PlayContext.class, GameContext.class, StringContext.class}, new String[] {"PlayContext$", "GameContext$", "StringContext$"}); // ensure two get play methods and both return hockey game int found1 = 0, bridge1 = 0; Method[] methods1 = ctor1.getDeclaringClass().getMethods(); for (Method method1 : methods1) { if (method1.getName().equals("getPlay")) { found1++; if (method1.isBridge()) { bridge1++; } } } assertEquals("expected two getPlay methods", 2, found1); assertEquals("expected one getPlay bridge method", 1, bridge1); // now build another constructor that merges that merge plus another // to ensure generics flow through from one merge to another Constructor<?> ctor2 = MergedClass.getConstructor2( ClassInjector.getInstance(this.getClass().getClassLoader()), new Class[] {ctor1.getDeclaringClass(), Dog.class}); // ensure two get play methods and both return hockey game int found2 = 0, bridge2 = 0; Method[] methods2 = ctor2.getDeclaringClass().getMethods(); for (Method method2 : methods2) { if (method2.getName().equals("getPlay")) { found2++; if (method2.isBridge()) { bridge2++; } } } assertEquals("expected two getPlay methods", 2, found1); assertEquals("expected one getPlay bridge method", 1, bridge1); // ensure get plays method has generic signature for list Method playsMethod = ctor2.getDeclaringClass().getMethod("getPlays"); Type returnType = playsMethod.getGenericReturnType(); assertTrue("expected param type", returnType instanceof ParameterizedType); assertEquals( "expected plays type for type param", HockeyGamePlayLog.class, ((ParameterizedType) returnType).getActualTypeArguments()[0]); }
public static List<ButtonInfo> computeButtonsForClass(Class<?> someClass, String list) { List<ButtonInfo> buttons = new ArrayList<ButtonInfo>(); for (Method method : someClass.getMethods()) { if (method.isBridge() || method.isSynthetic()) { continue; } Button button = getButtonForMethod(method, list); if (button != null) { ButtonInfo buttonInfo = new ButtonInfo(button, method, someClass); buttons.add(buttonInfo); } } Collections.sort(buttons, new ButtonComparatorByOrder()); // Group together buttons of the same group for (int i = 0; i < buttons.size() - 1; i++) { ButtonInfo info = buttons.get(i); String group = info.getButton().group(); if (!StringUtils.isBlank(group)) { int count = 1; for (int j = i + 1; j < buttons.size(); j++) { ButtonInfo info2 = buttons.get(j); if (info2.getButton().group().equals(group)) { buttons.remove(j); buttons.add(i + count, info2); count++; } } } } return buttons; }
/** List all class methods, including inherited and private. Inheritance duplicates cleared */ public List<JaversMethod> getAllMethods() { List<JaversMethod> methods = new ArrayList<>(); Set<Integer> added = new HashSet<>(); TypeResolvingContext context = new TypeResolvingContext(); Class clazz = methodSource; while (clazz != null) { context.addTypeSubstitutions(clazz); for (Method m : clazz.getDeclaredMethods()) { if (m.isBridge()) { continue; } int methodKey = methodKey(m); if (added.contains(methodKey)) { // System.out.println("filtered inheritance duplicate" +m); continue; } methods.add(createJMethod(m, context)); added.add(methodKey); } clazz = clazz.getSuperclass(); } return methods; }
public List<ProviderMethod<?>> getProviderMethods(Binder binder) { System.out.println("end"); List<ProviderMethod<?>> result = Lists.newArrayList(); Multimap<Signature, Method> methodsBySignature = HashMultimap.create(); for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) { for (Method method : c.getDeclaredMethods()) { // private/static methods cannot override or be overridden by other methods, so there is no // point in indexing them. // Skip synthetic methods and bridge methods since java will automatically generate // synthetic overrides in some cases where we don't want to generate an error (e.g. // increasing visibility of a subclass). if (((method.getModifiers() & (Modifier.PRIVATE | Modifier.STATIC)) == 0) && !method.isBridge() && !method.isSynthetic()) { methodsBySignature.put(new Signature(method), method); } Optional<Annotation> annotation = isProvider(binder, method); if (annotation.isPresent()) { result.add(createProviderMethod(binder, method, annotation.get())); } } } // we have found all the providers and now need to identify if any were overridden // In the worst case this will have O(n^2) in the number of @Provides methods, but that is only // assuming that every method is an override, in general it should be very quick. for (ProviderMethod<?> provider : result) { Method method = provider.getMethod(); for (Method matchingSignature : methodsBySignature.get(new Signature(method))) { // matching signature is in the same class or a super class, therefore method cannot be // overridding it. if (matchingSignature.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) { continue; } // now we know matching signature is in a subtype of method.getDeclaringClass() if (overrides(matchingSignature, method)) { String annotationString = provider.getAnnotation().annotationType() == Provides.class ? "@Provides" : "@" + provider.getAnnotation().annotationType().getCanonicalName(); binder.addError( "Overriding " + annotationString + " methods is not allowed." + "\n\t" + annotationString + " method: %s\n\toverridden by: %s", method, matchingSignature); break; } } } return result; }
public static Method getBridgeMethod(Class<?> clazz, String name, Class<?>... parameterTypes) throws Exception { Method method = clazz.getMethod(name, parameterTypes); if (method.isBridge()) { return method; } bridge: for (Method currentMethod : clazz.getMethods()) { if (!currentMethod.isBridge() || !name.equals(currentMethod.getName())) { continue; } Class<?>[] currentParameterTypes = currentMethod.getParameterTypes(); if (currentParameterTypes.length != parameterTypes.length) { continue; } for (int i = 0; i < currentParameterTypes.length; i++) { if (!currentParameterTypes[i].isAssignableFrom(parameterTypes[i])) { continue bridge; } } return currentMethod; } throw new NoSuchMethodException( "No bridge method on " + clazz + " with name " + name + " and parameter types " + Arrays.toString(parameterTypes)); }
protected boolean _isIncludableMethod(Method m, MethodFilter filter) { if (filter != null && !filter.includeMethod(m)) { return false; } /* 07-Apr-2009, tatu: Looks like generics can introduce hidden * bridge and/or synthetic methods. I don't think we want to * consider those... */ if (m.isSynthetic() || m.isBridge()) { return false; } return true; }
/** * Bridge/bridged method setup code copied from {@link * org.springframework.core.BridgeMethodResolverTests#testWithGenericParameter()}. * * @since 4.2 */ @Test public void findMergedAnnotationAttributesFromBridgeMethod() throws NoSuchMethodException { Method[] methods = StringGenericParameter.class.getMethods(); Method bridgeMethod = null; Method bridgedMethod = null; for (Method method : methods) { if ("getFor".equals(method.getName()) && !method.getParameterTypes()[0].equals(Integer.class)) { if (method.getReturnType().equals(Object.class)) { bridgeMethod = method; } else { bridgedMethod = method; } } } assertTrue(bridgeMethod != null && bridgeMethod.isBridge()); assertTrue(bridgedMethod != null && !bridgedMethod.isBridge()); AnnotationAttributes attributes = findMergedAnnotationAttributes(bridgeMethod, Order.class); assertNotNull( "Should find @Order on StringGenericParameter.getFor() bridge method", attributes); }
/** * Checks that the method found through reflection matches the specification from the API xml * file. */ private void checkMethodCompliance() { for (JDiffMethod method : jDiffMethods) { try { // this is because jdiff think a method in an interface is not abstract if (JDiffType.INTERFACE.equals(mClassType)) { method.mModifier |= Modifier.ABSTRACT; } Method m = findMatchingMethod(method); if (m == null) { mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.MISSING_METHOD, method.toReadableString(mAbsoluteClassName), "No method with correct signature found:" + method.toSignatureString()); } else { if (m.isVarArgs()) { method.mModifier |= METHOD_MODIFIER_VAR_ARGS; } if (m.isBridge()) { method.mModifier |= METHOD_MODIFIER_BRIDGE; } if (m.isSynthetic()) { method.mModifier |= METHOD_MODIFIER_SYNTHETIC; } // FIXME: A workaround to fix the final mismatch on enumeration if (mClass.isEnum() && method.mName.equals("values")) { return; } if (!areMethodModifiedCompatibile(method, m)) { mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.MISMATCH_METHOD, method.toReadableString(mAbsoluteClassName), "Non-compatible method found when looking for " + method.toSignatureString()); } } } catch (Exception e) { SignatureTestLog.e("Got exception when checking method compliance", e); mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.CAUGHT_EXCEPTION, method.toReadableString(mAbsoluteClassName), "Exception!"); } } }
/** * Returns true if the method is a provider. * * <p>Synthetic bridge methods are excluded. Starting with JDK 8, javac copies annotations onto * bridge methods (which always have erased signatures). */ private Optional<Annotation> isProvider(Binder binder, Method method) { if (method.isBridge() || method.isSynthetic()) { return Optional.absent(); } Annotation annotation = null; for (Class<? extends Annotation> annotationClass : scanner.annotationClasses()) { Annotation foundAnnotation = method.getAnnotation(annotationClass); if (foundAnnotation != null) { if (annotation != null) { binder.addError( "More than one annotation claimed by %s on method %s." + " Methods can only have one annotation claimed per scanner.", scanner, method); return Optional.absent(); } annotation = foundAnnotation; } } return Optional.fromNullable(annotation); }
@SuppressWarnings("unchecked") private <U extends DefaultGroupSequenceProvider<?>> DefaultGroupSequenceProvider<T> newGroupSequenceProviderInstance(Class<U> providerClass) { Method[] providerMethods = getMethods(providerClass); for (Method method : providerMethods) { Class<?>[] paramTypes = method.getParameterTypes(); if ("getValidationGroups".equals(method.getName()) && !method.isBridge() && paramTypes.length == 1 && paramTypes[0].isAssignableFrom(beanClass)) { return (DefaultGroupSequenceProvider<T>) newInstance(providerClass, "the default group sequence provider"); } } throw new GroupDefinitionException( "The default group sequence provider defined for " + beanClass.getName() + " has the wrong type"); }
private void addUniqueMethods(HashMap<String, Method> uniqueMethods, Method[] methods) { for (Method currentMethod : methods) { if (!currentMethod.isBridge()) { String signature = getSignature(currentMethod); // check to see if the method is already known // if it is known, then an extended class must have // overridden a method if (!uniqueMethods.containsKey(signature)) { if (canAccessPrivateMethods()) { try { currentMethod.setAccessible(true); } catch (Exception e) { // Ignored. This is only a final precaution, nothing we can do. } } uniqueMethods.put(signature, currentMethod); } } } }
private static Method getMethod(Class theClass, String propertyName) { Method[] methods = theClass.getDeclaredMethods(); Method.setAccessible(methods, true); for (Method method : methods) { // if the method has parameters, skip it // if ( method.getParameterTypes().length != 0 ) { // continue; // } // if the method is a "bridge", skip it if (method.isBridge()) { continue; } final String methodName = method.getName(); if (methodName.equals(propertyName)) { return method; } } return null; }
/** * Validates whether the given method is a valid candidate for Camel Bean Binding. * * @param clazz the class * @param method the method * @return true if valid, false to skip the method */ protected boolean isValidMethod(Class<?> clazz, Method method) { // must not be in the excluded list for (Method excluded : EXCLUDED_METHODS) { if (ObjectHelper.isOverridingMethod(excluded, method)) { // the method is overriding an excluded method so its not valid return false; } } // must be a public method if (!Modifier.isPublic(method.getModifiers())) { return false; } // return type must not be an Exchange and it should not be a bridge method if ((method.getReturnType() != null && Exchange.class.isAssignableFrom(method.getReturnType())) || method.isBridge()) { return false; } return true; }
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // We conveniently mock abstract methods be default if (Modifier.isAbstract(method.getModifiers())) { return handler.invoke(obj, method, args); } // Here I need to check if the fillInStackTrace was called by EasyMock inner code // If it's the case, just ignore the call. We ignore it for two reasons // 1- In Java 7, the fillInStackTrace won't work because, since no constructor was called, the // stackTrace attribute is null // 2- There might be some unexpected side effect in the original fillInStackTrace. So it seems // more logical to ignore the call if (obj instanceof Throwable && method.getName().equals("fillInStackTrace")) { if (isCallerMockInvocationHandlerInvoke(new Throwable())) { return obj; } } // Bridges should delegate to their bridged method. It should be done before // checking for mocked methods because only unbridged method are mocked // It also make sure the method passed to the handler is not the bridge. Normally it // shouldn't be necessary because bridges are never mocked so are never in the mockedMethods // map. So the normal case is that is will call invokeSuper which will call the interceptor // for // the bridged method. The problem is that it doesn't happen. It looks like a cglib bug. For // package scoped bridges (see GenericTest), the interceptor is not called for the bridged // method. Not normal from my point of view. if (method.isBridge()) { method = BridgeMethodResolver.findBridgedMethod(method); } if (mockedMethods != null && !mockedMethods.contains(method)) { return proxy.invokeSuper(obj, args); } return handler.invoke(obj, method, args); }
public List<Method> filter(List<Method> methods) { List<Method> annotatedCandidates = new ArrayList<Method>(); List<Method> fallbackCandidates = new ArrayList<Method>(); for (Method method : methods) { if (method.isBridge()) { continue; } if (this.requiresReply && method.getReturnType().equals(void.class)) { continue; } if (StringUtils.hasText(this.methodName) && !this.methodName.equals(method.getName())) { continue; } if (this.annotationType != null && AnnotationUtils.findAnnotation(method, this.annotationType) != null) { annotatedCandidates.add(method); } else { fallbackCandidates.add(method); } } return (!annotatedCandidates.isEmpty()) ? annotatedCandidates : fallbackCandidates; }
// copied from org.hibernate.internal.util.ReflectHelper private static Method getterMethod(Class theClass, String propertyName) { Method[] methods = theClass.getDeclaredMethods(); Method.setAccessible(methods, true); for (Method method : methods) { // if the method has parameters, skip it if (method.getParameterTypes().length != 0) { continue; } // if the method is a "bridge", skip it if (method.isBridge()) { continue; } final String methodName = method.getName(); // try "get" if (methodName.startsWith("get") || methodName.startsWith("has")) { String testStdMethod = Introspector.decapitalize(methodName.substring(3)); String testOldMethod = methodName.substring(3); if (testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName)) { return method; } } // if not "get", then try "is" if (methodName.startsWith("is")) { String testStdMethod = Introspector.decapitalize(methodName.substring(2)); String testOldMethod = methodName.substring(2); if (testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName)) { return method; } } } return null; }
@Override public boolean apply(final Method method) { return method.isBridge(); }
public static AnnotatedEndpointFactory create( final Class<?> endpointClass, final EncodingFactory encodingFactory, final Set<String> paths) throws DeploymentException { final Set<Class<? extends Annotation>> found = new HashSet<>(); BoundMethod onOpen = null; BoundMethod onClose = null; BoundMethod onError = null; BoundMethod textMessage = null; BoundMethod binaryMessage = null; BoundMethod pongMessage = null; Class<?> c = endpointClass; do { for (final Method method : c.getDeclaredMethods()) { if (method.isAnnotationPresent(OnOpen.class)) { if (found.contains(OnOpen.class)) { if (!onOpen.overrides(method)) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnOpen.class); } else { continue; } } found.add(OnOpen.class); onOpen = new BoundMethod( method, null, false, 0, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(method, EndpointConfig.class, true), createBoundPathParameters(method, paths, endpointClass)); } if (method.isAnnotationPresent(OnClose.class)) { if (found.contains(OnClose.class)) { if (!onClose.overrides(method)) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnClose.class); } else { continue; } } found.add(OnClose.class); onClose = new BoundMethod( method, null, false, 0, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(method, CloseReason.class, true), createBoundPathParameters(method, paths, endpointClass)); } if (method.isAnnotationPresent(OnError.class)) { if (found.contains(OnError.class)) { if (!onError.overrides(method)) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnError.class); } else { continue; } } found.add(OnError.class); onError = new BoundMethod( method, null, false, 0, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(method, Throwable.class, false), createBoundPathParameters(method, paths, endpointClass)); } if (method.isAnnotationPresent(OnMessage.class) && !method.isBridge()) { if (binaryMessage != null && binaryMessage.overrides(method)) { continue; } if (textMessage != null && textMessage.overrides(method)) { continue; } if (pongMessage != null && pongMessage.overrides(method)) { continue; } long maxMessageSize = method.getAnnotation(OnMessage.class).maxMessageSize(); boolean messageHandled = false; // this is a bit more complex Class<?>[] parameterTypes = method.getParameterTypes(); int booleanLocation = -1; for (int i = 0; i < parameterTypes.length; ++i) { if (hasAnnotation(PathParam.class, method.getParameterAnnotations()[i])) { continue; } final Class<?> param = parameterTypes[i]; if (param == boolean.class || param == Boolean.class) { booleanLocation = i; } else if (encodingFactory.canDecodeText(param)) { if (textMessage != null) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnMessage.class); } textMessage = new BoundMethod( method, param, true, maxMessageSize, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(method, boolean.class, true), new BoundSingleParameter(i, param), createBoundPathParameters(method, paths, endpointClass)); messageHandled = true; break; } else if (encodingFactory.canDecodeBinary(param)) { if (binaryMessage != null) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnMessage.class); } binaryMessage = new BoundMethod( method, param, true, maxMessageSize, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(method, boolean.class, true), new BoundSingleParameter(i, param), createBoundPathParameters(method, paths, endpointClass)); messageHandled = true; break; } else if (param.equals(byte[].class)) { if (binaryMessage != null) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnMessage.class); } binaryMessage = new BoundMethod( method, byte[].class, false, maxMessageSize, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(method, boolean.class, true), new BoundSingleParameter(i, byte[].class), createBoundPathParameters(method, paths, endpointClass)); messageHandled = true; break; } else if (param.equals(ByteBuffer.class)) { if (binaryMessage != null) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnMessage.class); } binaryMessage = new BoundMethod( method, ByteBuffer.class, false, maxMessageSize, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(method, boolean.class, true), new BoundSingleParameter(i, ByteBuffer.class), createBoundPathParameters(method, paths, endpointClass)); messageHandled = true; break; } else if (param.equals(InputStream.class)) { if (binaryMessage != null) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnMessage.class); } binaryMessage = new BoundMethod( method, InputStream.class, false, maxMessageSize, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(method, boolean.class, true), new BoundSingleParameter(i, InputStream.class), createBoundPathParameters(method, paths, endpointClass)); messageHandled = true; break; } else if (param.equals(String.class) && getPathParam(method, i) == null) { if (textMessage != null) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnMessage.class); } textMessage = new BoundMethod( method, String.class, false, maxMessageSize, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(method, boolean.class, true), new BoundSingleParameter(i, String.class), createBoundPathParameters(method, paths, endpointClass)); messageHandled = true; break; } else if (param.equals(Reader.class) && getPathParam(method, i) == null) { if (textMessage != null) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnMessage.class); } textMessage = new BoundMethod( method, Reader.class, false, maxMessageSize, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(method, boolean.class, true), new BoundSingleParameter(i, Reader.class), createBoundPathParameters(method, paths, endpointClass)); messageHandled = true; break; } else if (param.equals(PongMessage.class)) { if (pongMessage != null) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnMessage.class); } pongMessage = new BoundMethod( method, PongMessage.class, false, maxMessageSize, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(i, PongMessage.class), createBoundPathParameters(method, paths, endpointClass)); messageHandled = true; break; } } if (!messageHandled && booleanLocation != -1) { // so it turns out that the boolean was the message type and not a final fragement // indicator if (textMessage != null) { throw JsrWebSocketMessages.MESSAGES.moreThanOneAnnotation(OnMessage.class); } Class<?> boolClass = parameterTypes[booleanLocation]; textMessage = new BoundMethod( method, boolClass, true, maxMessageSize, new BoundSingleParameter(method, Session.class, true), new BoundSingleParameter(method, boolean.class, true), new BoundSingleParameter(booleanLocation, boolClass), createBoundPathParameters(method, paths, endpointClass)); messageHandled = true; } if (!messageHandled) { throw JsrWebSocketMessages.MESSAGES.couldNotFindMessageParameter(method); } } } c = c.getSuperclass(); } while (c != Object.class && c != null); return new AnnotatedEndpointFactory( endpointClass, onOpen, onClose, onError, textMessage, binaryMessage, pongMessage); }
public int accept(Method method, List<Method> allMethods) { return method.isBridge() ? 1 : 0; }
public boolean matches(Method method) { return !method.isBridge(); }
public boolean matches(Method method) { return (!method.isBridge() && method.getDeclaringClass() != Object.class); }
/** {@inheritDoc} */ public int accept(final Method method) { return method.isBridge() || method.getName().equals("finalize") && method.getParameterTypes().length == 0 ? 1 : 0; }
/** * Returns true if the method is eligible to be injected. This is different than {@link * #isValidMethod}, because ineligibility will not drop a method from being injected if a * superclass was eligible & valid. Bridge & synthetic methods are excluded from eligibility for * two reasons: * * <p>Prior to Java8, javac would generate these methods in subclasses without annotations, which * means this would accidentally stop injecting a method annotated with {@link * javax.inject.Inject}, since the spec says to stop injecting if a subclass isn't annotated with * it. * * <p>Starting at Java8, javac copies the annotations to the generated subclass method, except it * leaves out the generic types. If this considered it a valid injectable method, this would eject * the parent's overridden method that had the proper generic types, and would use invalid * injectable parameters as a result. * * <p>The fix for both is simply to ignore these synthetic bridge methods. */ private static boolean isEligibleForInjection(Method method, boolean statics) { return Modifier.isStatic(method.getModifiers()) == statics && !method.isBridge() && !method.isSynthetic(); }