public static LinkedHashMap<String, Type> fillOuterGenerics(
            final Type type,
            final LinkedHashMap<String, Type> generics,
            final Map<Class<?>, LinkedHashMap<String, Type>> knownGenerics) {
        final LinkedHashMap<String, Type> res;
        final Type outer = TypeUtils.getOuter(type);
        if (outer == null) {
            // not inner class
            res = generics;
        } else {
            final LinkedHashMap<String, Type> outerGenerics;
            if (outer instanceof ParameterizedType) {
                // outer generics declared in field definition (ignorance required because provided type
                // may contain unknown outer generics (Outer<B>.Inner field))
                outerGenerics = resolveGenerics(outer, new IgnoreGenericsMap(generics));
            } else {
                final Class<?> outerType = GenericsUtils.resolveClass(outer, generics);
                // either use known generics for outer class or resolve by upper bound
                outerGenerics = knownGenerics != null && knownGenerics.containsKey(outerType)
                        ? new LinkedHashMap<String, Type>(knownGenerics.get(outerType))
                        : resolveRawGenerics(outerType);
            }
            // class may declare generics with the same name and they must not be overridden
            for (TypeVariable var : GenericsUtils.resolveClass(type, generics).getTypeParameters()) {
                outerGenerics.remove(var.getName());
            }

            if (generics instanceof EmptyGenericsMap) {
                // if outer map is empty then it was assumed that empty map could be returned
                // (outerGenerics could be empty map too)
                res = outerGenerics;
            } else {
                generics.putAll(outerGenerics);
                res = generics;
            }
        }
        return res;
    }
public static LinkedHashMap < String , Type > fillOuterGenerics ( final Type type , final LinkedHashMap < String , Type > generics , final Map < Class < ? > , LinkedHashMap < String , Type > > knownGenerics ) { final LinkedHashMap < String , Type > res ; final Type outer = TypeUtils . getOuter ( type ) ; if ( outer == null ) { res = generics ; } else { final LinkedHashMap < String , Type > outerGenerics ; if ( outer instanceof ParameterizedType ) { outerGenerics = resolveGenerics ( outer , new IgnoreGenericsMap ( generics ) ) ; } else { final Class < ? > outerType = GenericsUtils . resolveClass ( outer , generics ) ; outerGenerics = knownGenerics != null && knownGenerics . containsKey ( outerType ) ? new LinkedHashMap < String , Type > ( knownGenerics . get ( outerType ) ) : resolveRawGenerics ( outerType ) ; } for ( TypeVariable var : GenericsUtils . resolveClass ( type , generics ) . getTypeParameters ( ) ) { outerGenerics . remove ( var . getName ( ) ) ; } if ( generics instanceof EmptyGenericsMap ) { res = outerGenerics ; } else { generics . putAll ( outerGenerics ) ; res = generics ; } } return res ; }
Inner class could reference outer class generics and so this generics must be included into class context.
<p>
Outer generics could be included into declaration like {@code Outer<String>.Inner field}. In this case
incoming type should be {@link ParameterizedType} with generified owner.
<p>
When provided type is simply a class (or anything resolvable to class), then outer class generics are resolved
as upper bound (by declaration). Class may declare the same generic name and, in this case, outer generic
will be ignored (as not visible).
<p>
During inlying context resolution, if outer generic is not declared in type we can try to guess it:
we know outer context, and, if outer class is in outer context hierarchy, we could assume that it's actual
parent class and so we could use more specific generics. This will be true for most sane cases (often inner
class is used inside owner), but other cases are still possible (anyway, the chance that inner class will
appear in two different hierarchies of outer class is quite small).
<p>
It is very important to use returned map instead of passed in map because, incoming empty map is always replaced
to avoid modifications of shared empty maps.

@param type          context type
@param generics      resolved type generics
@param knownGenerics map of known middle generics and possibly known outer context (outer context may contain
outer class generics declarations). May be null.
@return actual generics map (incoming map may be default empty map and in this case it must be replaced)