code: 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);
  
          }
      }
docs: 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