code: public static boolean isGroovyAssignableFrom(Class<?> leftType, Class<?> rightType) {
          if (leftType == null) {
              throw new NullPointerException("Left type is null!");
          }
          if (rightType == null) {
              throw new NullPointerException("Right type is null!");
          }
          if (leftType == Object.class) {
              return true;
          }
          if (leftType == rightType) {
              return true;
          }
          // check for primitive type equivalence
          Class<?> r = PRIMITIVE_TYPE_COMPATIBLE_CLASSES.get(leftType);
          boolean result = r == rightType;
  
          if (!result) {
              // If no primitive <-> wrapper match, it may still be assignable
              // from polymorphic primitives i.e. Number -> int (AKA Integer)
              if (rightType.isPrimitive()) {
                  // see if incompatible
                  r = PRIMITIVE_TYPE_COMPATIBLE_CLASSES.get(rightType);
                  if (r != null) {
                      result = leftType.isAssignableFrom(r);
                  }
              }
              else {
                  // Otherwise it may just be assignable using normal Java polymorphism
                  result = leftType.isAssignableFrom(rightType);
              }
          }
          return result;
      }
docs: <p>Tests whether or not the left hand type is compatible with the right hand type in Groovy
  terms, i.e. can the left type be assigned a value of the right hand type in Groovy.</p>
  <p>This handles Java primitive type equivalence and uses isAssignableFrom for all other types,
  with a bit of magic for native types and polymorphism i.e. Number assigned an int.
  If either parameter is null an exception is thrown</p>
  
  @param leftType The type of the left hand part of a notional assignment
  @param rightType The type of the right hand part of a notional assignment
  @return true if values of the right hand type can be assigned in Groovy to variables of the left hand type.