@SuppressWarnings("checkstyle:CyclomaticComplexity")
    private static boolean isCompatible(final Type one, final Type two) {
        final Class[] oneBounds = GenericsUtils.resolveUpperBounds(one, IGNORE_VARS);
        final Class[] twoBounds = GenericsUtils.resolveUpperBounds(two, IGNORE_VARS);

        boolean res = true;
        final boolean oneWildcard = one instanceof WildcardType;
        final boolean twoWildcard = two instanceof WildcardType;
        if (oneWildcard || twoWildcard) {

            // check if both wildcards are lower bounded (? super)
            if (oneWildcard && twoWildcard) {
                res = isLowerBoundsCompatible((WildcardType) one, (WildcardType) two);
            }

            // check if left wildcard is lower bounded (? super Something)
            if (res && oneWildcard) {
                res = isLowerBoundCompatible((WildcardType) one, twoBounds);
            }

            // check if right wildcard is lower bounded (? super Something)
            if (res && twoWildcard) {
                res = isLowerBoundCompatible((WildcardType) two, oneBounds);
            }

            // compare upper bounds for compatibility (? extends Something)
            if (res) {
                res = TypeUtils.isAssignableBounds(oneBounds, twoBounds)
                        || TypeUtils.isAssignableBounds(twoBounds, oneBounds);
            }

        } else {
            // no wildcards - types must be simply assignable
            res = isCompatibleClasses(oneBounds[0], twoBounds[0]);
        }
        return res;
    }
@ SuppressWarnings ( "checkstyle:CyclomaticComplexity" ) private static boolean isCompatible ( final Type one , final Type two ) { final Class [ ] oneBounds = GenericsUtils . resolveUpperBounds ( one , IGNORE_VARS ) ; final Class [ ] twoBounds = GenericsUtils . resolveUpperBounds ( two , IGNORE_VARS ) ; boolean res = true ; final boolean oneWildcard = one instanceof WildcardType ; final boolean twoWildcard = two instanceof WildcardType ; if ( oneWildcard || twoWildcard ) { if ( oneWildcard && twoWildcard ) { res = isLowerBoundsCompatible ( ( WildcardType ) one , ( WildcardType ) two ) ; } if ( res && oneWildcard ) { res = isLowerBoundCompatible ( ( WildcardType ) one , twoBounds ) ; } if ( res && twoWildcard ) { res = isLowerBoundCompatible ( ( WildcardType ) two , oneBounds ) ; } if ( res ) { res = TypeUtils . isAssignableBounds ( oneBounds , twoBounds ) || TypeUtils . isAssignableBounds ( twoBounds , oneBounds ) ; } } else { res = isCompatibleClasses ( oneBounds [ 0 ] , twoBounds [ 0 ] ) ; } return res ; }
Check if one types are wildcards and apply wildcard rules:
<ul>
<li>Wildcard with multiple upper bounds (repackaged T extends A & B) must be checked against all bounds</li>
<li>Wildcard with lower bound (? super A) compatible only with A and it's supertypes</li>
</ul>
<p>
Non wildcard types are projected to class

@param one type to check
@param two type to check with
@return true if types compatible according to wildcard rules