public static Type resolveRawGeneric(final TypeVariable variable,
                                         final LinkedHashMap<String, Type> generics) {
        final Type res;
        if (variable.getBounds().length > 1) {
            // case: T extends A & B -->  ? extends A & B
            final List<Type> types = new ArrayList<Type>();
            for (Type bound : variable.getBounds()) {
                // replace possible named generics with actual type (for cases like K extends T)
                final Type actual = GenericsUtils.resolveTypeVariables(bound, generics);
                if (actual instanceof WildcardType && ((WildcardType) actual).getUpperBounds().length > 0) {
                    // case: T extends A & B, K extends T & C --> K must be aggregated as ? extends A & B & C
                    // this case is impossible in java, but allowed in groovy
                    types.addAll(Arrays.asList(GenericsUtils
                            .resolveTypeVariables(((WildcardType) actual).getUpperBounds(), generics)));
                } else {
                    types.add(actual);
                }
            }
            // case: T extends Object & Something (may appear because of transitive generics resolution)
            // only one object could appear (because wildcard could only be
            // ? extends type (or generic) & exact interface (& exact interface))
            // (repackaged from type declaration)
            types.remove(Object.class);
            if (types.size() > 1) {
                // repackaging as impossible wildcard <? extends A & B> to store all known information
                res = WildcardTypeImpl.upper(types.toArray(new Type[0]));
            } else {
                // if one type remain - use it directly; if no types remain - use Object
                res = types.isEmpty() ? Object.class : types.get(0);
            }
        } else {
            // case: simple generic declaration <T> (implicitly extends Object)
            res = GenericsUtils.resolveTypeVariables(variable.getBounds()[0], generics);
        }
        return res;
    }
public static Type resolveRawGeneric ( final TypeVariable variable , final LinkedHashMap < String , Type > generics ) { final Type res ; if ( variable . getBounds ( ) . length > 1 ) { final List < Type > types = new ArrayList < Type > ( ) ; for ( Type bound : variable . getBounds ( ) ) { final Type actual = GenericsUtils . resolveTypeVariables ( bound , generics ) ; if ( actual instanceof WildcardType && ( ( WildcardType ) actual ) . getUpperBounds ( ) . length > 0 ) { types . addAll ( Arrays . asList ( GenericsUtils . resolveTypeVariables ( ( ( WildcardType ) actual ) . getUpperBounds ( ) , generics ) ) ) ; } else { types . add ( actual ) ; } } types . remove ( Object . class ) ; if ( types . size ( ) > 1 ) { res = WildcardTypeImpl . upper ( types . toArray ( new Type [ 0 ] ) ) ; } else { res = types . isEmpty ( ) ? Object . class : types . get ( 0 ) ; } } else { res = GenericsUtils . resolveTypeVariables ( variable . getBounds ( ) [ 0 ] , generics ) ; } return res ; }
Extracts declared upper bound from generic declaration. For example, {@code Base<T>} will be resolved
as Object (default bound). {@code Base<T extends A & B>} resolved as "impossible" wildcard
{@code ? extends A & B} in order to preserve all known information.
<p>
Map of already resolved generics is required because declaration may rely on them. For example,
{@code Base<T extends Serializable, K extends T>} could be solved as {@code T = Serializable, K = Serializable}.

@param variable generic declaration to analyze
@param generics already resolved generics (on the left of current)
@return either upper bound class or wildcard with multiple bounds