public static ClassNode lowestUpperBound(ClassNode a, ClassNode b) {
        ClassNode lub = lowestUpperBound(a, b, null, null);
        if (lub==null || !lub.isUsingGenerics()) return lub;
        // types may be parameterized. If so, we must ensure that generic type arguments
        // are made compatible

        if (lub instanceof LowestUpperBoundClassNode) {
            // no parent super class representing both types could be found
            // or both class nodes implement common interfaces which may have
            // been parameterized differently.
            // We must create a classnode for which the "superclass" is potentially parameterized
            // plus the interfaces
            ClassNode superClass = lub.getSuperClass();
            ClassNode psc = superClass.isUsingGenerics()?parameterizeLowestUpperBound(superClass, a, b, lub):superClass;

            ClassNode[] interfaces = lub.getInterfaces();
            ClassNode[] pinterfaces = new ClassNode[interfaces.length];
            for (int i = 0, interfacesLength = interfaces.length; i < interfacesLength; i++) {
                final ClassNode icn = interfaces[i];
                if (icn.isUsingGenerics()) {
                    pinterfaces[i] = parameterizeLowestUpperBound(icn, a, b, lub);
                } else {
                    pinterfaces[i] = icn;
                }
            }

            return new LowestUpperBoundClassNode(((LowestUpperBoundClassNode)lub).name, psc, pinterfaces);
        } else {
            return parameterizeLowestUpperBound(lub, a, b, lub);

        }
    }
public static ClassNode lowestUpperBound ( ClassNode a , ClassNode b ) { ClassNode lub = lowestUpperBound ( a , b , null , null ) ; if ( lub == null || ! lub . isUsingGenerics ( ) ) return lub ; if ( lub instanceof LowestUpperBoundClassNode ) { ClassNode superClass = lub . getSuperClass ( ) ; ClassNode psc = superClass . isUsingGenerics ( ) ? parameterizeLowestUpperBound ( superClass , a , b , lub ) : superClass ; ClassNode [ ] interfaces = lub . getInterfaces ( ) ; ClassNode [ ] pinterfaces = new ClassNode [ interfaces . length ] ; for ( int i = 0 , interfacesLength = interfaces . length ; i < interfacesLength ; i ++ ) { final ClassNode icn = interfaces [ i ] ; if ( icn . isUsingGenerics ( ) ) { pinterfaces [ i ] = parameterizeLowestUpperBound ( icn , a , b , lub ) ; } else { pinterfaces [ i ] = icn ; } } return new LowestUpperBoundClassNode ( ( ( LowestUpperBoundClassNode ) lub ) . name , psc , pinterfaces ) ; } else { return parameterizeLowestUpperBound ( lub , a , b , lub ) ; } }
Given two class nodes, returns the first common supertype, or the class itself
if there are equal. For example, Double and Float would return Number, while
Set and String would return Object.

This method is not guaranteed to return a class node which corresponds to a
real type. For example, if two types have more than one interface in common
and are not in the same hierarchy branch, then the returned type will be a
virtual type implementing all those interfaces.

Calls to this method are supposed to be made with resolved generics. This means
that you can have wildcards, but no placeholder.

@param a first class node
@param b second class node
@return first common supertype