Coverage Report - org.apache.commons.lang3.reflect.TypeUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
TypeUtils
65%
300/455
54%
219/400
4,974
TypeUtils$1
100%
2/2
N/A
4,974
TypeUtils$GenericArrayTypeImpl
60%
6/10
0%
0/6
4,974
TypeUtils$ParameterizedTypeImpl
61%
11/18
50%
3/6
4,974
TypeUtils$WildcardTypeBuilder
75%
6/8
N/A
4,974
TypeUtils$WildcardTypeImpl
53%
8/15
0%
0/6
4,974
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.lang3.reflect;
 18  
 
 19  
 import java.lang.reflect.Array;
 20  
 import java.lang.reflect.GenericArrayType;
 21  
 import java.lang.reflect.GenericDeclaration;
 22  
 import java.lang.reflect.ParameterizedType;
 23  
 import java.lang.reflect.Type;
 24  
 import java.lang.reflect.TypeVariable;
 25  
 import java.lang.reflect.WildcardType;
 26  
 import java.util.Arrays;
 27  
 import java.util.Collections;
 28  
 import java.util.HashMap;
 29  
 import java.util.HashSet;
 30  
 import java.util.List;
 31  
 import java.util.Map;
 32  
 import java.util.Set;
 33  
 
 34  
 import org.apache.commons.lang3.ArrayUtils;
 35  
 import org.apache.commons.lang3.ClassUtils;
 36  
 import org.apache.commons.lang3.ObjectUtils;
 37  
 import org.apache.commons.lang3.Validate;
 38  
 import org.apache.commons.lang3.builder.Builder;
 39  
 
 40  
 /**
 41  
  * <p> Utility methods focusing on type inspection, particularly with regard to
 42  
  * generics. </p>
 43  
  *
 44  
  * @since 3.0
 45  
  * @version $Id: TypeUtils.java 1583482 2014-03-31 22:54:57Z niallp $
 46  
  */
 47  2
 public class TypeUtils {
 48  
 
 49  
     /**
 50  
      * {@link WildcardType} builder.
 51  
      * @since 3.2
 52  
      */
 53  3
     public static class WildcardTypeBuilder implements Builder<WildcardType> {
 54  
         /**
 55  
          * Constructor
 56  
          */
 57  3
         private WildcardTypeBuilder() {
 58  3
         }
 59  
         
 60  
         private Type[] upperBounds;
 61  
         private Type[] lowerBounds;
 62  
 
 63  
         /**
 64  
          * Specify upper bounds of the wildcard type to build.
 65  
          * @param bounds to set
 66  
          * @return {@code this}
 67  
          */
 68  
         public WildcardTypeBuilder withUpperBounds(Type... bounds) {
 69  3
             this.upperBounds = bounds;
 70  3
             return this;
 71  
         }
 72  
 
 73  
         /**
 74  
          * Specify lower bounds of the wildcard type to build.
 75  
          * @param bounds to set
 76  
          * @return {@code this}
 77  
          */
 78  
         public WildcardTypeBuilder withLowerBounds(Type... bounds) {
 79  0
             this.lowerBounds = bounds;
 80  0
             return this;
 81  
         }
 82  
 
 83  
         /**
 84  
          * {@inheritDoc}
 85  
          */
 86  
         @Override
 87  
         public WildcardType build() {
 88  3
             return new WildcardTypeImpl(upperBounds, lowerBounds);
 89  
         }
 90  
     }
 91  
 
 92  
     /**
 93  
      * GenericArrayType implementation class.
 94  
      * @since 3.2 
 95  
      */
 96  1
     private static final class GenericArrayTypeImpl implements GenericArrayType {
 97  
         private final Type componentType;
 98  
 
 99  
         /**
 100  
          * Constructor
 101  
          * @param componentType of this array type
 102  
          */
 103  1
         private GenericArrayTypeImpl(Type componentType) {
 104  1
             this.componentType = componentType;
 105  1
         }
 106  
 
 107  
         /**
 108  
          * {@inheritDoc}
 109  
          */
 110  
         @Override
 111  
         public Type getGenericComponentType() {
 112  2
             return componentType;
 113  
         }
 114  
 
 115  
         /**
 116  
          * {@inheritDoc}
 117  
          */
 118  
         @Override
 119  
         public String toString() {
 120  1
             return TypeUtils.toString(this);
 121  
         }
 122  
 
 123  
         /**
 124  
          * {@inheritDoc}
 125  
          */
 126  
         @Override
 127  
         public boolean equals(Object obj) {
 128  0
             return obj == this || obj instanceof GenericArrayType && TypeUtils.equals(this, (GenericArrayType) obj);
 129  
         }
 130  
 
 131  
         /**
 132  
          * {@inheritDoc}
 133  
          */
 134  
         @Override
 135  
         public int hashCode() {
 136  0
             int result = 67 << 4;
 137  0
             result |= componentType.hashCode();
 138  0
             return result;
 139  
         }
 140  
     }
 141  
 
 142  
     /**
 143  
      * ParameterizedType implementation class.
 144  
      * @since 3.2 
 145  
      */
 146  6
     private static final class ParameterizedTypeImpl implements ParameterizedType {
 147  
         private final Class<?> raw;
 148  
         private final Type useOwner;
 149  
         private final Type[] typeArguments;
 150  
 
 151  
         /**
 152  
          * Constructor
 153  
          * @param raw type
 154  
          * @param useOwner owner type to use, if any
 155  
          * @param typeArguments formal type arguments
 156  
          */
 157  6
         private ParameterizedTypeImpl(Class<?> raw, Type useOwner, Type[] typeArguments) {
 158  6
             this.raw = raw;
 159  6
             this.useOwner = useOwner;
 160  6
             this.typeArguments = typeArguments;
 161  6
         }
 162  
 
 163  
         /**
 164  
          * {@inheritDoc}
 165  
          */
 166  
         @Override
 167  
         public Type getRawType() {
 168  9
             return raw;
 169  
         }
 170  
 
 171  
         /**
 172  
          * {@inheritDoc}
 173  
          */
 174  
         @Override
 175  
         public Type getOwnerType() {
 176  8
             return useOwner;
 177  
         }
 178  
 
 179  
         /**
 180  
          * {@inheritDoc}
 181  
          */
 182  
         @Override
 183  
         public Type[] getActualTypeArguments() {
 184  8
             return typeArguments.clone();
 185  
         }
 186  
 
 187  
         /**
 188  
          * {@inheritDoc}
 189  
          */
 190  
         @Override
 191  
         public String toString() {
 192  1
             return TypeUtils.toString(this);
 193  
         }
 194  
 
 195  
         /**
 196  
          * {@inheritDoc}
 197  
          */
 198  
         @Override
 199  
         public boolean equals(Object obj) {
 200  2
             return obj == this || obj instanceof ParameterizedType && TypeUtils.equals(this, ((ParameterizedType) obj));
 201  
         }
 202  
 
 203  
         /**
 204  
          * {@inheritDoc}
 205  
          */
 206  
         @SuppressWarnings( "deprecation" )  // ObjectUtils.hashCode(Object) has been deprecated in 3.2
 207  
         @Override
 208  
         public int hashCode() {
 209  0
             int result = 71 << 4;
 210  0
             result |= raw.hashCode();
 211  0
             result <<= 4;
 212  0
             result |= ObjectUtils.hashCode(useOwner);
 213  0
             result <<= 8;
 214  0
             result |= Arrays.hashCode(typeArguments);
 215  0
             return result;
 216  
         }
 217  
     }
 218  
 
 219  
     /**
 220  
      * WildcardType implementation class.
 221  
      * @since 3.2 
 222  
      */
 223  3
     private static final class WildcardTypeImpl implements WildcardType {
 224  1
         private static final Type[] EMPTY_BOUNDS = new Type[0];
 225  
 
 226  
         private final Type[] upperBounds;
 227  
         private final Type[] lowerBounds;
 228  
 
 229  
         /**
 230  
          * Constructor
 231  
          * @param upperBounds of this type
 232  
          * @param lowerBounds of this type
 233  
          */
 234  3
         private WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
 235  3
             this.upperBounds = ObjectUtils.defaultIfNull(upperBounds, EMPTY_BOUNDS);
 236  3
             this.lowerBounds = ObjectUtils.defaultIfNull(lowerBounds, EMPTY_BOUNDS);
 237  3
         }
 238  
 
 239  
         /**
 240  
          * {@inheritDoc}
 241  
          */
 242  
         @Override
 243  
         public Type[] getUpperBounds() {
 244  3
             return upperBounds.clone();
 245  
         }
 246  
 
 247  
         /**
 248  
          * {@inheritDoc}
 249  
          */
 250  
         @Override
 251  
         public Type[] getLowerBounds() {
 252  3
             return lowerBounds.clone();
 253  
         }
 254  
 
 255  
         /**
 256  
          * {@inheritDoc}
 257  
          */
 258  
         @Override
 259  
         public String toString() {
 260  0
             return TypeUtils.toString(this);
 261  
         }
 262  
 
 263  
         /**
 264  
          * {@inheritDoc}
 265  
          */
 266  
         @Override
 267  
         public boolean equals(Object obj) {
 268  0
             return obj == this || obj instanceof WildcardType && TypeUtils.equals(this, (WildcardType) obj);
 269  
         }
 270  
 
 271  
         /**
 272  
          * {@inheritDoc}
 273  
          */
 274  
         @Override
 275  
         public int hashCode() {
 276  0
             int result = 73 << 8;
 277  0
             result |= Arrays.hashCode(upperBounds);
 278  0
             result <<= 8;
 279  0
             result |= Arrays.hashCode(lowerBounds);
 280  0
             return result;
 281  
         }
 282  
     }
 283  
 
 284  
     /**
 285  
      * A wildcard instance matching {@code ?}.
 286  
      * @since 3.2
 287  
      */
 288  1
     public static final WildcardType WILDCARD_ALL = wildcardType().withUpperBounds(Object.class).build();
 289  
 
 290  
     /**
 291  
      * <p>{@code TypeUtils} instances should NOT be constructed in standard
 292  
      * programming. Instead, the class should be used as
 293  
      * {@code TypeUtils.isAssignable(cls, toClass)}.</p> <p>This
 294  
      * constructor is public to permit tools that require a JavaBean instance to
 295  
      * operate.</p>
 296  
      */
 297  
     public TypeUtils() {
 298  0
         super();
 299  0
     }
 300  
 
 301  
     /**
 302  
      * <p>Checks if the subject type may be implicitly cast to the target type
 303  
      * following the Java generics rules. If both types are {@link Class}
 304  
      * objects, the method returns the result of
 305  
      * {@link ClassUtils#isAssignable(Class, Class)}.</p>
 306  
      *
 307  
      * @param type the subject type to be assigned to the target type
 308  
      * @param toType the target type
 309  
      * @return {@code true} if {@code type} is assignable to {@code toType}.
 310  
      */
 311  
     public static boolean isAssignable(final Type type, final Type toType) {
 312  170
         return isAssignable(type, toType, null);
 313  
     }
 314  
 
 315  
     /**
 316  
      * <p>Checks if the subject type may be implicitly cast to the target type
 317  
      * following the Java generics rules.</p>
 318  
      *
 319  
      * @param type the subject type to be assigned to the target type
 320  
      * @param toType the target type
 321  
      * @param typeVarAssigns optional map of type variable assignments
 322  
      * @return {@code true} if {@code type} is assignable to {@code toType}.
 323  
      */
 324  
     private static boolean isAssignable(final Type type, final Type toType,
 325  
             final Map<TypeVariable<?>, Type> typeVarAssigns) {
 326  336
         if (toType == null || toType instanceof Class<?>) {
 327  143
             return isAssignable(type, (Class<?>) toType);
 328  
         }
 329  
 
 330  193
         if (toType instanceof ParameterizedType) {
 331  106
             return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
 332  
         }
 333  
 
 334  87
         if (toType instanceof GenericArrayType) {
 335  43
             return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
 336  
         }
 337  
 
 338  44
         if (toType instanceof WildcardType) {
 339  44
             return isAssignable(type, (WildcardType) toType, typeVarAssigns);
 340  
         }
 341  
 
 342  0
         if (toType instanceof TypeVariable<?>) {
 343  0
             return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
 344  
         }
 345  
 
 346  0
         throw new IllegalStateException("found an unhandled type: " + toType);
 347  
     }
 348  
 
 349  
     /**
 350  
      * <p>Checks if the subject type may be implicitly cast to the target class
 351  
      * following the Java generics rules.</p>
 352  
      *
 353  
      * @param type the subject type to be assigned to the target type
 354  
      * @param toClass the target class
 355  
      * @return {@code true} if {@code type} is assignable to {@code toClass}.
 356  
      */
 357  
     private static boolean isAssignable(final Type type, final Class<?> toClass) {
 358  543
         if (type == null) {
 359  
             // consistency with ClassUtils.isAssignable() behavior
 360  44
             return toClass == null || !toClass.isPrimitive();
 361  
         }
 362  
 
 363  
         // only a null type can be assigned to null type which
 364  
         // would have cause the previous to return true
 365  499
         if (toClass == null) {
 366  8
             return false;
 367  
         }
 368  
 
 369  
         // all types are assignable to themselves
 370  491
         if (toClass.equals(type)) {
 371  322
             return true;
 372  
         }
 373  
 
 374  169
         if (type instanceof Class<?>) {
 375  
             // just comparing two classes
 376  150
             return ClassUtils.isAssignable((Class<?>) type, toClass);
 377  
         }
 378  
 
 379  19
         if (type instanceof ParameterizedType) {
 380  
             // only have to compare the raw type to the class
 381  13
             return isAssignable(getRawType((ParameterizedType) type), toClass);
 382  
         }
 383  
 
 384  
         // *
 385  6
         if (type instanceof TypeVariable<?>) {
 386  
             // if any of the bounds are assignable to the class, then the
 387  
             // type is assignable to the class.
 388  0
             for (final Type bound : ((TypeVariable<?>) type).getBounds()) {
 389  0
                 if (isAssignable(bound, toClass)) {
 390  0
                     return true;
 391  
                 }
 392  
             }
 393  
 
 394  0
             return false;
 395  
         }
 396  
 
 397  
         // the only classes to which a generic array type can be assigned
 398  
         // are class Object and array classes
 399  6
         if (type instanceof GenericArrayType) {
 400  6
             return toClass.equals(Object.class)
 401  
                     || toClass.isArray()
 402  
                     && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass
 403  
                             .getComponentType());
 404  
         }
 405  
 
 406  
         // wildcard types are not assignable to a class (though one would think
 407  
         // "? super Object" would be assignable to Object)
 408  0
         if (type instanceof WildcardType) {
 409  0
             return false;
 410  
         }
 411  
 
 412  0
         throw new IllegalStateException("found an unhandled type: " + type);
 413  
     }
 414  
 
 415  
     /**
 416  
      * <p>Checks if the subject type may be implicitly cast to the target
 417  
      * parameterized type following the Java generics rules.</p>
 418  
      *
 419  
      * @param type the subject type to be assigned to the target type
 420  
      * @param toParameterizedType the target parameterized type
 421  
      * @param typeVarAssigns a map with type variables
 422  
      * @return {@code true} if {@code type} is assignable to {@code toType}.
 423  
      */
 424  
     private static boolean isAssignable(final Type type, final ParameterizedType toParameterizedType,
 425  
             final Map<TypeVariable<?>, Type> typeVarAssigns) {
 426  106
         if (type == null) {
 427  0
             return true;
 428  
         }
 429  
 
 430  
         // only a null type can be assigned to null type which
 431  
         // would have cause the previous to return true
 432  106
         if (toParameterizedType == null) {
 433  0
             return false;
 434  
         }
 435  
 
 436  
         // all types are assignable to themselves
 437  106
         if (toParameterizedType.equals(type)) {
 438  6
             return true;
 439  
         }
 440  
 
 441  
         // get the target type's raw type
 442  100
         final Class<?> toClass = getRawType(toParameterizedType);
 443  
         // get the subject type's type arguments including owner type arguments
 444  
         // and supertype arguments up to and including the target class.
 445  100
         final Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
 446  
 
 447  
         // null means the two types are not compatible
 448  100
         if (fromTypeVarAssigns == null) {
 449  0
             return false;
 450  
         }
 451  
 
 452  
         // compatible types, but there's no type arguments. this is equivalent
 453  
         // to comparing Map< ?, ? > to Map, and raw types are always assignable
 454  
         // to parameterized types.
 455  100
         if (fromTypeVarAssigns.isEmpty()) {
 456  12
             return true;
 457  
         }
 458  
 
 459  
         // get the target type's type arguments including owner type arguments
 460  88
         final Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType,
 461  
                 toClass, typeVarAssigns);
 462  
 
 463  
         // now to check each type argument
 464  88
         for (final TypeVariable<?> var : toTypeVarAssigns.keySet()) {
 465  97
             final Type toTypeArg = unrollVariableAssignments(var, toTypeVarAssigns);
 466  97
             final Type fromTypeArg = unrollVariableAssignments(var, fromTypeVarAssigns);
 467  
 
 468  
             // parameters must either be absent from the subject type, within
 469  
             // the bounds of the wildcard type, or be an exact match to the
 470  
             // parameters of the target type.
 471  97
             if (fromTypeArg != null
 472  
                     && !toTypeArg.equals(fromTypeArg)
 473  
                     && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg,
 474  
                             typeVarAssigns))) {
 475  49
                 return false;
 476  
             }
 477  48
         }
 478  39
         return true;
 479  
     }
 480  
 
 481  
     /**
 482  
      * Look up {@code var} in {@code typeVarAssigns} <em>transitively</em>,
 483  
      * i.e. keep looking until the value found is <em>not</em> a type variable.
 484  
      * @param var the type variable to look up
 485  
      * @param typeVarAssigns the map used for the look up
 486  
      * @return Type or {@code null} if some variable was not in the map
 487  
      * @since 3.2
 488  
      */
 489  
     private static Type unrollVariableAssignments(TypeVariable<?> var, final Map<TypeVariable<?>, Type> typeVarAssigns) {
 490  
         Type result;
 491  
         do {
 492  198
             result = typeVarAssigns.get(var);
 493  198
             if (result instanceof TypeVariable<?> && !result.equals(var)) {
 494  4
                 var = (TypeVariable<?>) result;
 495  4
                 continue;
 496  
             }
 497  
             break;
 498  
         } while (true);
 499  194
         return result;
 500  
     }
 501  
 
 502  
     /**
 503  
      * <p>Checks if the subject type may be implicitly cast to the target
 504  
      * generic array type following the Java generics rules.</p>
 505  
      *
 506  
      * @param type the subject type to be assigned to the target type
 507  
      * @param toGenericArrayType the target generic array type
 508  
      * @param typeVarAssigns a map with type variables
 509  
      * @return {@code true} if {@code type} is assignable to
 510  
      * {@code toGenericArrayType}.
 511  
      */
 512  
     private static boolean isAssignable(final Type type, final GenericArrayType toGenericArrayType,
 513  
             final Map<TypeVariable<?>, Type> typeVarAssigns) {
 514  43
         if (type == null) {
 515  0
             return true;
 516  
         }
 517  
 
 518  
         // only a null type can be assigned to null type which
 519  
         // would have cause the previous to return true
 520  43
         if (toGenericArrayType == null) {
 521  0
             return false;
 522  
         }
 523  
 
 524  
         // all types are assignable to themselves
 525  43
         if (toGenericArrayType.equals(type)) {
 526  6
             return true;
 527  
         }
 528  
 
 529  37
         final Type toComponentType = toGenericArrayType.getGenericComponentType();
 530  
 
 531  37
         if (type instanceof Class<?>) {
 532  7
             final Class<?> cls = (Class<?>) type;
 533  
 
 534  
             // compare the component types
 535  7
             return cls.isArray()
 536  
                     && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
 537  
         }
 538  
 
 539  30
         if (type instanceof GenericArrayType) {
 540  
             // compare the component types
 541  30
             return isAssignable(((GenericArrayType) type).getGenericComponentType(),
 542  
                     toComponentType, typeVarAssigns);
 543  
         }
 544  
 
 545  0
         if (type instanceof WildcardType) {
 546  
             // so long as one of the upper bounds is assignable, it's good
 547  0
             for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
 548  0
                 if (isAssignable(bound, toGenericArrayType)) {
 549  0
                     return true;
 550  
                 }
 551  
             }
 552  
 
 553  0
             return false;
 554  
         }
 555  
 
 556  0
         if (type instanceof TypeVariable<?>) {
 557  
             // probably should remove the following logic and just return false.
 558  
             // type variables cannot specify arrays as bounds.
 559  0
             for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
 560  0
                 if (isAssignable(bound, toGenericArrayType)) {
 561  0
                     return true;
 562  
                 }
 563  
             }
 564  
 
 565  0
             return false;
 566  
         }
 567  
 
 568  0
         if (type instanceof ParameterizedType) {
 569  
             // the raw type of a parameterized type is never an array or
 570  
             // generic array, otherwise the declaration would look like this:
 571  
             // Collection[]< ? extends String > collection;
 572  0
             return false;
 573  
         }
 574  
 
 575  0
         throw new IllegalStateException("found an unhandled type: " + type);
 576  
     }
 577  
 
 578  
     /**
 579  
      * <p>Checks if the subject type may be implicitly cast to the target
 580  
      * wildcard type following the Java generics rules.</p>
 581  
      *
 582  
      * @param type the subject type to be assigned to the target type
 583  
      * @param toWildcardType the target wildcard type
 584  
      * @param typeVarAssigns a map with type variables
 585  
      * @return {@code true} if {@code type} is assignable to
 586  
      * {@code toWildcardType}.
 587  
      */
 588  
     private static boolean isAssignable(final Type type, final WildcardType toWildcardType,
 589  
             final Map<TypeVariable<?>, Type> typeVarAssigns) {
 590  44
         if (type == null) {
 591  0
             return true;
 592  
         }
 593  
 
 594  
         // only a null type can be assigned to null type which
 595  
         // would have cause the previous to return true
 596  44
         if (toWildcardType == null) {
 597  0
             return false;
 598  
         }
 599  
 
 600  
         // all types are assignable to themselves
 601  44
         if (toWildcardType.equals(type)) {
 602  0
             return true;
 603  
         }
 604  
 
 605  44
         final Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
 606  44
         final Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
 607  
 
 608  44
         if (type instanceof WildcardType) {
 609  24
             final WildcardType wildcardType = (WildcardType) type;
 610  24
             final Type[] upperBounds = getImplicitUpperBounds(wildcardType);
 611  24
             final Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
 612  
 
 613  42
             for (Type toBound : toUpperBounds) {
 614  
                 // if there are assignments for unresolved type variables,
 615  
                 // now's the time to substitute them.
 616  24
                 toBound = substituteTypeVariables(toBound, typeVarAssigns);
 617  
 
 618  
                 // each upper bound of the subject type has to be assignable to
 619  
                 // each
 620  
                 // upper bound of the target type
 621  42
                 for (final Type bound : upperBounds) {
 622  24
                     if (!isAssignable(bound, toBound, typeVarAssigns)) {
 623  6
                         return false;
 624  
                     }
 625  
                 }
 626  
             }
 627  
 
 628  26
             for (Type toBound : toLowerBounds) {
 629  
                 // if there are assignments for unresolved type variables,
 630  
                 // now's the time to substitute them.
 631  18
                 toBound = substituteTypeVariables(toBound, typeVarAssigns);
 632  
 
 633  
                 // each lower bound of the target type has to be assignable to
 634  
                 // each
 635  
                 // lower bound of the subject type
 636  26
                 for (final Type bound : lowerBounds) {
 637  18
                     if (!isAssignable(toBound, bound, typeVarAssigns)) {
 638  10
                         return false;
 639  
                     }
 640  
                 }
 641  
             }
 642  8
             return true;
 643  
         }
 644  
 
 645  38
         for (final Type toBound : toUpperBounds) {
 646  
             // if there are assignments for unresolved type variables,
 647  
             // now's the time to substitute them.
 648  20
             if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns),
 649  
                     typeVarAssigns)) {
 650  2
                 return false;
 651  
             }
 652  
         }
 653  
 
 654  34
         for (final Type toBound : toLowerBounds) {
 655  
             // if there are assignments for unresolved type variables,
 656  
             // now's the time to substitute them.
 657  18
             if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type,
 658  
                     typeVarAssigns)) {
 659  2
                 return false;
 660  
             }
 661  
         }
 662  16
         return true;
 663  
     }
 664  
 
 665  
     /**
 666  
      * <p>Checks if the subject type may be implicitly cast to the target type
 667  
      * variable following the Java generics rules.</p>
 668  
      *
 669  
      * @param type the subject type to be assigned to the target type
 670  
      * @param toTypeVariable the target type variable
 671  
      * @param typeVarAssigns a map with type variables
 672  
      * @return {@code true} if {@code type} is assignable to
 673  
      * {@code toTypeVariable}.
 674  
      */
 675  
     private static boolean isAssignable(final Type type, final TypeVariable<?> toTypeVariable,
 676  
             final Map<TypeVariable<?>, Type> typeVarAssigns) {
 677  0
         if (type == null) {
 678  0
             return true;
 679  
         }
 680  
 
 681  
         // only a null type can be assigned to null type which
 682  
         // would have cause the previous to return true
 683  0
         if (toTypeVariable == null) {
 684  0
             return false;
 685  
         }
 686  
 
 687  
         // all types are assignable to themselves
 688  0
         if (toTypeVariable.equals(type)) {
 689  0
             return true;
 690  
         }
 691  
 
 692  0
         if (type instanceof TypeVariable<?>) {
 693  
             // a type variable is assignable to another type variable, if
 694  
             // and only if the former is the latter, extends the latter, or
 695  
             // is otherwise a descendant of the latter.
 696  0
             final Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
 697  
 
 698  0
             for (final Type bound : bounds) {
 699  0
                 if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
 700  0
                     return true;
 701  
                 }
 702  
             }
 703  
         }
 704  
 
 705  0
         if (type instanceof Class<?> || type instanceof ParameterizedType
 706  
                 || type instanceof GenericArrayType || type instanceof WildcardType) {
 707  0
             return false;
 708  
         }
 709  
 
 710  0
         throw new IllegalStateException("found an unhandled type: " + type);
 711  
     }
 712  
 
 713  
     /**
 714  
      * <p>Find the mapping for {@code type} in {@code typeVarAssigns}.</p>
 715  
      *
 716  
      * @param type the type to be replaced
 717  
      * @param typeVarAssigns the map with type variables
 718  
      * @return the replaced type
 719  
      * @throws IllegalArgumentException if the type cannot be substituted
 720  
      */
 721  
     private static Type substituteTypeVariables(final Type type, final Map<TypeVariable<?>, Type> typeVarAssigns) {
 722  83
         if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
 723  2
             final Type replacementType = typeVarAssigns.get(type);
 724  
 
 725  2
             if (replacementType == null) {
 726  0
                 throw new IllegalArgumentException("missing assignment type for type variable "
 727  
                         + type);
 728  
             }
 729  2
             return replacementType;
 730  
         }
 731  81
         return type;
 732  
     }
 733  
 
 734  
     /**
 735  
      * <p>Retrieves all the type arguments for this parameterized type
 736  
      * including owner hierarchy arguments such as
 737  
      * {@code Outer<K,V>.Inner<T>.DeepInner<E>} .
 738  
      * The arguments are returned in a
 739  
      * {@link Map} specifying the argument type for each {@link TypeVariable}.
 740  
      * </p>
 741  
      *
 742  
      * @param type specifies the subject parameterized type from which to
 743  
      *             harvest the parameters.
 744  
      * @return a {@code Map} of the type arguments to their respective type
 745  
      * variables.
 746  
      */
 747  
     public static Map<TypeVariable<?>, Type> getTypeArguments(final ParameterizedType type) {
 748  0
         return getTypeArguments(type, getRawType(type), null);
 749  
     }
 750  
 
 751  
     /**
 752  
      * <p>Gets the type arguments of a class/interface based on a subtype. For
 753  
      * instance, this method will determine that both of the parameters for the
 754  
      * interface {@link Map} are {@link Object} for the subtype
 755  
      * {@link java.util.Properties Properties} even though the subtype does not
 756  
      * directly implement the {@code Map} interface.</p>
 757  
      * <p>This method returns {@code null} if {@code type} is not assignable to
 758  
      * {@code toClass}. It returns an empty map if none of the classes or
 759  
      * interfaces in its inheritance hierarchy specify any type arguments.</p>
 760  
      * <p>A side effect of this method is that it also retrieves the type
 761  
      * arguments for the classes and interfaces that are part of the hierarchy
 762  
      * between {@code type} and {@code toClass}. So with the above
 763  
      * example, this method will also determine that the type arguments for
 764  
      * {@link java.util.Hashtable Hashtable} are also both {@code Object}.
 765  
      * In cases where the interface specified by {@code toClass} is
 766  
      * (indirectly) implemented more than once (e.g. where {@code toClass}
 767  
      * specifies the interface {@link java.lang.Iterable Iterable} and
 768  
      * {@code type} specifies a parameterized type that implements both
 769  
      * {@link java.util.Set Set} and {@link java.util.Collection Collection}),
 770  
      * this method will look at the inheritance hierarchy of only one of the
 771  
      * implementations/subclasses; the first interface encountered that isn't a
 772  
      * subinterface to one of the others in the {@code type} to
 773  
      * {@code toClass} hierarchy.</p>
 774  
      *
 775  
      * @param type the type from which to determine the type parameters of
 776  
      * {@code toClass}
 777  
      * @param toClass the class whose type parameters are to be determined based
 778  
      * on the subtype {@code type}
 779  
      * @return a {@code Map} of the type assignments for the type variables in
 780  
      * each type in the inheritance hierarchy from {@code type} to
 781  
      * {@code toClass} inclusive.
 782  
      */
 783  
     public static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass) {
 784  52
         return getTypeArguments(type, toClass, null);
 785  
     }
 786  
 
 787  
     /**
 788  
      * <p>Return a map of the type arguments of @{code type} in the context of {@code toClass}.</p>
 789  
      *
 790  
      * @param type the type in question
 791  
      * @param toClass the class
 792  
      * @param subtypeVarAssigns a map with type variables
 793  
      * @return the {@code Map} with type arguments
 794  
      */
 795  
     private static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass,
 796  
             final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
 797  240
         if (type instanceof Class<?>) {
 798  86
             return getTypeArguments((Class<?>) type, toClass, subtypeVarAssigns);
 799  
         }
 800  
 
 801  154
         if (type instanceof ParameterizedType) {
 802  154
             return getTypeArguments((ParameterizedType) type, toClass, subtypeVarAssigns);
 803  
         }
 804  
 
 805  0
         if (type instanceof GenericArrayType) {
 806  0
             return getTypeArguments(((GenericArrayType) type).getGenericComponentType(), toClass
 807  
                     .isArray() ? toClass.getComponentType() : toClass, subtypeVarAssigns);
 808  
         }
 809  
 
 810  
         // since wildcard types are not assignable to classes, should this just
 811  
         // return null?
 812  0
         if (type instanceof WildcardType) {
 813  0
             for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
 814  
                 // find the first bound that is assignable to the target class
 815  0
                 if (isAssignable(bound, toClass)) {
 816  0
                     return getTypeArguments(bound, toClass, subtypeVarAssigns);
 817  
                 }
 818  
             }
 819  
 
 820  0
             return null;
 821  
         }
 822  
 
 823  0
         if (type instanceof TypeVariable<?>) {
 824  0
             for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
 825  
                 // find the first bound that is assignable to the target class
 826  0
                 if (isAssignable(bound, toClass)) {
 827  0
                     return getTypeArguments(bound, toClass, subtypeVarAssigns);
 828  
                 }
 829  
             }
 830  
 
 831  0
             return null;
 832  
         }
 833  0
         throw new IllegalStateException("found an unhandled type: " + type);
 834  
     }
 835  
 
 836  
     /**
 837  
      * <p>Return a map of the type arguments of a parameterized type in the context of {@code toClass}.</p>
 838  
      *
 839  
      * @param parameterizedType the parameterized type
 840  
      * @param toClass the class
 841  
      * @param subtypeVarAssigns a map with type variables
 842  
      * @return the {@code Map} with type arguments
 843  
      */
 844  
     private static Map<TypeVariable<?>, Type> getTypeArguments(
 845  
             final ParameterizedType parameterizedType, final Class<?> toClass,
 846  
             final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
 847  257
         final Class<?> cls = getRawType(parameterizedType);
 848  
 
 849  
         // make sure they're assignable
 850  257
         if (!isAssignable(cls, toClass)) {
 851  0
             return null;
 852  
         }
 853  
 
 854  257
         final Type ownerType = parameterizedType.getOwnerType();
 855  
         Map<TypeVariable<?>, Type> typeVarAssigns;
 856  
 
 857  257
         if (ownerType instanceof ParameterizedType) {
 858  
             // get the owner type arguments first
 859  14
             final ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
 860  14
             typeVarAssigns = getTypeArguments(parameterizedOwnerType,
 861  
                     getRawType(parameterizedOwnerType), subtypeVarAssigns);
 862  14
         } else {
 863  
             // no owner, prep the type variable assignments map
 864  243
             typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
 865  
                     : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
 866  
         }
 867  
 
 868  
         // get the subject parameterized type's arguments
 869  257
         final Type[] typeArgs = parameterizedType.getActualTypeArguments();
 870  
         // and get the corresponding type variables from the raw class
 871  257
         final TypeVariable<?>[] typeParams = cls.getTypeParameters();
 872  
 
 873  
         // map the arguments to their respective type variables
 874  535
         for (int i = 0; i < typeParams.length; i++) {
 875  278
             final Type typeArg = typeArgs[i];
 876  278
             typeVarAssigns.put(typeParams[i], typeVarAssigns.containsKey(typeArg) ? typeVarAssigns
 877  
                     .get(typeArg) : typeArg);
 878  
         }
 879  
 
 880  257
         if (toClass.equals(cls)) {
 881  
             // target class has been reached. Done.
 882  235
             return typeVarAssigns;
 883  
         }
 884  
 
 885  
         // walk the inheritance hierarchy until the target class is reached
 886  22
         return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
 887  
     }
 888  
 
 889  
     /**
 890  
      * <p>Return a map of the type arguments of a class in the context of @{code toClass}.</p>
 891  
      *
 892  
      * @param cls the class in question
 893  
      * @param toClass the context class
 894  
      * @param subtypeVarAssigns a map with type variables
 895  
      * @return the {@code Map} with type arguments
 896  
      */
 897  
     private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, final Class<?> toClass,
 898  
             final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
 899  
         // make sure they're assignable
 900  86
         if (!isAssignable(cls, toClass)) {
 901  0
             return null;
 902  
         }
 903  
 
 904  
         // can't work with primitives
 905  86
         if (cls.isPrimitive()) {
 906  
             // both classes are primitives?
 907  3
             if (toClass.isPrimitive()) {
 908  
                 // dealing with widening here. No type arguments to be
 909  
                 // harvested with these two types.
 910  0
                 return new HashMap<TypeVariable<?>, Type>();
 911  
             }
 912  
 
 913  
             // work with wrapper the wrapper class instead of the primitive
 914  3
             cls = ClassUtils.primitiveToWrapper(cls);
 915  
         }
 916  
 
 917  
         // create a copy of the incoming map, or an empty one if it's null
 918  86
         final HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
 919  
                 : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
 920  
 
 921  
         // has target class been reached?
 922  86
         if (toClass.equals(cls)) {
 923  20
             return typeVarAssigns;
 924  
         }
 925  
 
 926  
         // walk the inheritance hierarchy until the target class is reached
 927  66
         return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
 928  
     }
 929  
 
 930  
     /**
 931  
      * <p>Tries to determine the type arguments of a class/interface based on a
 932  
      * super parameterized type's type arguments. This method is the inverse of
 933  
      * {@link #getTypeArguments(Type, Class)} which gets a class/interface's
 934  
      * type arguments based on a subtype. It is far more limited in determining
 935  
      * the type arguments for the subject class's type variables in that it can
 936  
      * only determine those parameters that map from the subject {@link Class}
 937  
      * object to the supertype.</p> <p>Example: {@link java.util.TreeSet
 938  
      * TreeSet} sets its parameter as the parameter for
 939  
      * {@link java.util.NavigableSet NavigableSet}, which in turn sets the
 940  
      * parameter of {@link java.util.SortedSet}, which in turn sets the
 941  
      * parameter of {@link Set}, which in turn sets the parameter of
 942  
      * {@link java.util.Collection}, which in turn sets the parameter of
 943  
      * {@link java.lang.Iterable}. Since {@code TreeSet}'s parameter maps
 944  
      * (indirectly) to {@code Iterable}'s parameter, it will be able to
 945  
      * determine that based on the super type {@code Iterable<? extends
 946  
      * Map<Integer, ? extends Collection<?>>>}, the parameter of
 947  
      * {@code TreeSet} is {@code ? extends Map<Integer, ? extends
 948  
      * Collection<?>>}.</p>
 949  
      *
 950  
      * @param cls the class whose type parameters are to be determined, not {@code null}
 951  
      * @param superType the super type from which {@code cls}'s type
 952  
      * arguments are to be determined, not {@code null}
 953  
      * @return a {@code Map} of the type assignments that could be determined
 954  
      * for the type variables in each type in the inheritance hierarchy from
 955  
      * {@code type} to {@code toClass} inclusive.
 956  
      */
 957  
     public static Map<TypeVariable<?>, Type> determineTypeArguments(final Class<?> cls,
 958  
             final ParameterizedType superType) {
 959  6
         Validate.notNull(cls, "cls is null");
 960  6
         Validate.notNull(superType, "superType is null");
 961  
 
 962  6
         final Class<?> superClass = getRawType(superType);
 963  
 
 964  
         // compatibility check
 965  6
         if (!isAssignable(cls, superClass)) {
 966  0
             return null;
 967  
         }
 968  
 
 969  6
         if (cls.equals(superClass)) {
 970  1
             return getTypeArguments(superType, superClass, null);
 971  
         }
 972  
 
 973  
         // get the next class in the inheritance hierarchy
 974  5
         final Type midType = getClosestParentType(cls, superClass);
 975  
 
 976  
         // can only be a class or a parameterized type
 977  5
         if (midType instanceof Class<?>) {
 978  0
             return determineTypeArguments((Class<?>) midType, superType);
 979  
         }
 980  
 
 981  5
         final ParameterizedType midParameterizedType = (ParameterizedType) midType;
 982  5
         final Class<?> midClass = getRawType(midParameterizedType);
 983  
         // get the type variables of the mid class that map to the type
 984  
         // arguments of the super class
 985  5
         final Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superType);
 986  
         // map the arguments of the mid type to the class type variables
 987  5
         mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
 988  
 
 989  5
         return typeVarAssigns;
 990  
     }
 991  
 
 992  
     /**
 993  
      * <p>Performs a mapping of type variables.</p>
 994  
      *
 995  
      * @param <T> the generic type of the class in question
 996  
      * @param cls the class in question
 997  
      * @param parameterizedType the parameterized type
 998  
      * @param typeVarAssigns the map to be filled
 999  
      */
 1000  
     private static <T> void mapTypeVariablesToArguments(final Class<T> cls,
 1001  
             final ParameterizedType parameterizedType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
 1002  
         // capture the type variables from the owner type that have assignments
 1003  5
         final Type ownerType = parameterizedType.getOwnerType();
 1004  
 
 1005  5
         if (ownerType instanceof ParameterizedType) {
 1006  
             // recursion to make sure the owner's owner type gets processed
 1007  0
             mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
 1008  
         }
 1009  
 
 1010  
         // parameterizedType is a generic interface/class (or it's in the owner
 1011  
         // hierarchy of said interface/class) implemented/extended by the class
 1012  
         // cls. Find out which type variables of cls are type arguments of
 1013  
         // parameterizedType:
 1014  5
         final Type[] typeArgs = parameterizedType.getActualTypeArguments();
 1015  
 
 1016  
         // of the cls's type variables that are arguments of parameterizedType,
 1017  
         // find out which ones can be determined from the super type's arguments
 1018  5
         final TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
 1019  
 
 1020  
         // use List view of type parameters of cls so the contains() method can be used:
 1021  5
         final List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls
 1022  
                 .getTypeParameters());
 1023  
 
 1024  10
         for (int i = 0; i < typeArgs.length; i++) {
 1025  5
             final TypeVariable<?> typeVar = typeVars[i];
 1026  5
             final Type typeArg = typeArgs[i];
 1027  
 
 1028  
             // argument of parameterizedType is a type variable of cls
 1029  5
             if (typeVarList.contains(typeArg)
 1030  
             // type variable of parameterizedType has an assignment in
 1031  
                     // the super type.
 1032  
                     && typeVarAssigns.containsKey(typeVar)) {
 1033  
                 // map the assignment to the cls's type variable
 1034  5
                 typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
 1035  
             }
 1036  
         }
 1037  5
     }
 1038  
 
 1039  
     /**
 1040  
      * <p>Get the closest parent type to the
 1041  
      * super class specified by {@code superClass}.</p>
 1042  
      *
 1043  
      * @param cls the class in question
 1044  
      * @param superClass the super class
 1045  
      * @return the closes parent type
 1046  
      */
 1047  
     private static Type getClosestParentType(final Class<?> cls, final Class<?> superClass) {
 1048  
         // only look at the interfaces if the super class is also an interface
 1049  93
         if (superClass.isInterface()) {
 1050  
             // get the generic interfaces of the subject class
 1051  31
             final Type[] interfaceTypes = cls.getGenericInterfaces();
 1052  
             // will hold the best generic interface match found
 1053  31
             Type genericInterface = null;
 1054  
 
 1055  
             // find the interface closest to the super class
 1056  62
             for (final Type midType : interfaceTypes) {
 1057  31
                 Class<?> midClass = null;
 1058  
 
 1059  31
                 if (midType instanceof ParameterizedType) {
 1060  29
                     midClass = getRawType((ParameterizedType) midType);
 1061  2
                 } else if (midType instanceof Class<?>) {
 1062  2
                     midClass = (Class<?>) midType;
 1063  
                 } else {
 1064  0
                     throw new IllegalStateException("Unexpected generic"
 1065  
                             + " interface type found: " + midType);
 1066  
                 }
 1067  
 
 1068  
                 // check if this interface is further up the inheritance chain
 1069  
                 // than the previously found match
 1070  31
                 if (isAssignable(midClass, superClass)
 1071  
                         && isAssignable(genericInterface, (Type) midClass)) {
 1072  29
                     genericInterface = midType;
 1073  
                 }
 1074  
             }
 1075  
 
 1076  
             // found a match?
 1077  31
             if (genericInterface != null) {
 1078  29
                 return genericInterface;
 1079  
             }
 1080  
         }
 1081  
 
 1082  
         // none of the interfaces were descendants of the target class, so the
 1083  
         // super class has to be one, instead
 1084  64
         return cls.getGenericSuperclass();
 1085  
     }
 1086  
 
 1087  
     /**
 1088  
      * <p>Checks if the given value can be assigned to the target type
 1089  
      * following the Java generics rules.</p>
 1090  
      *
 1091  
      * @param value the value to be checked
 1092  
      * @param type the target type
 1093  
      * @return {@code true} if {@code value} is an instance of {@code type}.
 1094  
      */
 1095  
     public static boolean isInstance(final Object value, final Type type) {
 1096  2
         if (type == null) {
 1097  0
             return false;
 1098  
         }
 1099  
 
 1100  2
         return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()
 1101  
                 : isAssignable(value.getClass(), type, null);
 1102  
     }
 1103  
 
 1104  
     /**
 1105  
      * <p>This method strips out the redundant upper bound types in type
 1106  
      * variable types and wildcard types (or it would with wildcard types if
 1107  
      * multiple upper bounds were allowed).</p> <p>Example, with the variable
 1108  
      * type declaration:
 1109  
      *
 1110  
      * <pre>&lt;K extends java.util.Collection&lt;String&gt; &amp;
 1111  
      * java.util.List&lt;String&gt;&gt;</pre>
 1112  
      *
 1113  
      * <p>
 1114  
      * since {@code List} is a subinterface of {@code Collection},
 1115  
      * this method will return the bounds as if the declaration had been:
 1116  
      * </p>
 1117  
      *
 1118  
      * <pre>&lt;K extends java.util.List&lt;String&gt;&gt;</pre>
 1119  
      *
 1120  
      * @param bounds an array of types representing the upper bounds of either
 1121  
      * {@link WildcardType} or {@link TypeVariable}, not {@code null}.
 1122  
      * @return an array containing the values from {@code bounds} minus the
 1123  
      * redundant types.
 1124  
      */
 1125  
     public static Type[] normalizeUpperBounds(final Type[] bounds) {
 1126  72
         Validate.notNull(bounds, "null value specified for bounds array");
 1127  
         // don't bother if there's only one (or none) type
 1128  72
         if (bounds.length < 2) {
 1129  71
             return bounds;
 1130  
         }
 1131  
 
 1132  1
         final Set<Type> types = new HashSet<Type>(bounds.length);
 1133  
 
 1134  3
         for (final Type type1 : bounds) {
 1135  2
             boolean subtypeFound = false;
 1136  
 
 1137  6
             for (final Type type2 : bounds) {
 1138  4
                 if (type1 != type2 && isAssignable(type2, type1, null)) {
 1139  0
                     subtypeFound = true;
 1140  0
                     break;
 1141  
                 }
 1142  
             }
 1143  
 
 1144  2
             if (!subtypeFound) {
 1145  2
                 types.add(type1);
 1146  
             }
 1147  
         }
 1148  
 
 1149  1
         return types.toArray(new Type[types.size()]);
 1150  
     }
 1151  
 
 1152  
     /**
 1153  
      * <p>Returns an array containing the sole type of {@link Object} if
 1154  
      * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it
 1155  
      * returns the result of {@link TypeVariable#getBounds()} passed into
 1156  
      * {@link #normalizeUpperBounds}.</p>
 1157  
      *
 1158  
      * @param typeVariable the subject type variable, not {@code null}
 1159  
      * @return a non-empty array containing the bounds of the type variable.
 1160  
      */
 1161  
     public static Type[] getImplicitBounds(final TypeVariable<?> typeVariable) {
 1162  3
         Validate.notNull(typeVariable, "typeVariable is null");
 1163  3
         final Type[] bounds = typeVariable.getBounds();
 1164  
 
 1165  3
         return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
 1166  
     }
 1167  
 
 1168  
     /**
 1169  
      * <p>Returns an array containing the sole value of {@link Object} if
 1170  
      * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise,
 1171  
      * it returns the result of {@link WildcardType#getUpperBounds()}
 1172  
      * passed into {@link #normalizeUpperBounds}.</p>
 1173  
      *
 1174  
      * @param wildcardType the subject wildcard type, not {@code null}
 1175  
      * @return a non-empty array containing the upper bounds of the wildcard
 1176  
      * type.
 1177  
      */
 1178  
     public static Type[] getImplicitUpperBounds(final WildcardType wildcardType) {
 1179  68
         Validate.notNull(wildcardType, "wildcardType is null");
 1180  68
         final Type[] bounds = wildcardType.getUpperBounds();
 1181  
 
 1182  68
         return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
 1183  
     }
 1184  
 
 1185  
     /**
 1186  
      * <p>Returns an array containing a single value of {@code null} if
 1187  
      * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise,
 1188  
      * it returns the result of {@link WildcardType#getLowerBounds()}.</p>
 1189  
      *
 1190  
      * @param wildcardType the subject wildcard type, not {@code null}
 1191  
      * @return a non-empty array containing the lower bounds of the wildcard
 1192  
      * type.
 1193  
      */
 1194  
     public static Type[] getImplicitLowerBounds(final WildcardType wildcardType) {
 1195  68
         Validate.notNull(wildcardType, "wildcardType is null");
 1196  68
         final Type[] bounds = wildcardType.getLowerBounds();
 1197  
 
 1198  68
         return bounds.length == 0 ? new Type[] { null } : bounds;
 1199  
     }
 1200  
 
 1201  
     /**
 1202  
      * <p>Determines whether or not specified types satisfy the bounds of their
 1203  
      * mapped type variables. When a type parameter extends another (such as
 1204  
      * {@code <T, S extends T>}), uses another as a type parameter (such as
 1205  
      * {@code <T, S extends Comparable>>}), or otherwise depends on
 1206  
      * another type variable to be specified, the dependencies must be included
 1207  
      * in {@code typeVarAssigns}.</p>
 1208  
      *
 1209  
      * @param typeVarAssigns specifies the potential types to be assigned to the
 1210  
      * type variables, not {@code null}.
 1211  
      * @return whether or not the types can be assigned to their respective type
 1212  
      * variables.
 1213  
      */
 1214  
     public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVarAssigns) {
 1215  3
         Validate.notNull(typeVarAssigns, "typeVarAssigns is null");
 1216  
         // all types must be assignable to all the bounds of the their mapped
 1217  
         // type variable.
 1218  3
         for (final Map.Entry<TypeVariable<?>, Type> entry : typeVarAssigns.entrySet()) {
 1219  3
             final TypeVariable<?> typeVar = entry.getKey();
 1220  3
             final Type type = entry.getValue();
 1221  
 
 1222  6
             for (final Type bound : getImplicitBounds(typeVar)) {
 1223  3
                 if (!isAssignable(type, substituteTypeVariables(bound, typeVarAssigns),
 1224  
                         typeVarAssigns)) {
 1225  0
                     return false;
 1226  
                 }
 1227  
             }
 1228  3
         }
 1229  3
         return true;
 1230  
     }
 1231  
 
 1232  
     /**
 1233  
      * <p>Transforms the passed in type to a {@link Class} object. Type-checking method of convenience.</p>
 1234  
      *
 1235  
      * @param parameterizedType the type to be converted
 1236  
      * @return the corresponding {@code Class} object
 1237  
      * @throws IllegalStateException if the conversion fails
 1238  
      */
 1239  
     private static Class<?> getRawType(final ParameterizedType parameterizedType) {
 1240  433
         final Type rawType = parameterizedType.getRawType();
 1241  
 
 1242  
         // check if raw type is a Class object
 1243  
         // not currently necessary, but since the return type is Type instead of
 1244  
         // Class, there's enough reason to believe that future versions of Java
 1245  
         // may return other Type implementations. And type-safety checking is
 1246  
         // rarely a bad idea.
 1247  433
         if (!(rawType instanceof Class<?>)) {
 1248  0
             throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType);
 1249  
         }
 1250  
 
 1251  433
         return (Class<?>) rawType;
 1252  
     }
 1253  
 
 1254  
     /**
 1255  
      * <p>Get the raw type of a Java type, given its context. Primarily for use
 1256  
      * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
 1257  
      * not know the runtime type of {@code type}: if you know you have a
 1258  
      * {@link Class} instance, it is already raw; if you know you have a
 1259  
      * {@link ParameterizedType}, its raw type is only a method call away.</p>
 1260  
      *
 1261  
      * @param type to resolve
 1262  
      * @param assigningType type to be resolved against
 1263  
      * @return the resolved {@link Class} object or {@code null} if
 1264  
      * the type could not be resolved
 1265  
      */
 1266  
     public static Class<?> getRawType(final Type type, final Type assigningType) {
 1267  14
         if (type instanceof Class<?>) {
 1268  
             // it is raw, no problem
 1269  4
             return (Class<?>) type;
 1270  
         }
 1271  
 
 1272  10
         if (type instanceof ParameterizedType) {
 1273  
             // simple enough to get the raw type of a ParameterizedType
 1274  4
             return getRawType((ParameterizedType) type);
 1275  
         }
 1276  
 
 1277  6
         if (type instanceof TypeVariable<?>) {
 1278  5
             if (assigningType == null) {
 1279  0
                 return null;
 1280  
             }
 1281  
 
 1282  
             // get the entity declaring this type variable
 1283  5
             final Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
 1284  
 
 1285  
             // can't get the raw type of a method- or constructor-declared type
 1286  
             // variable
 1287  5
             if (!(genericDeclaration instanceof Class<?>)) {
 1288  0
                 return null;
 1289  
             }
 1290  
 
 1291  
             // get the type arguments for the declaring class/interface based
 1292  
             // on the enclosing type
 1293  5
             final Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType,
 1294  
                     (Class<?>) genericDeclaration);
 1295  
 
 1296  
             // enclosingType has to be a subclass (or subinterface) of the
 1297  
             // declaring type
 1298  5
             if (typeVarAssigns == null) {
 1299  0
                 return null;
 1300  
             }
 1301  
 
 1302  
             // get the argument assigned to this type variable
 1303  5
             final Type typeArgument = typeVarAssigns.get(type);
 1304  
 
 1305  5
             if (typeArgument == null) {
 1306  1
                 return null;
 1307  
             }
 1308  
 
 1309  
             // get the argument for this type variable
 1310  4
             return getRawType(typeArgument, assigningType);
 1311  
         }
 1312  
 
 1313  1
         if (type instanceof GenericArrayType) {
 1314  
             // get raw component type
 1315  1
             final Class<?> rawComponentType = getRawType(((GenericArrayType) type)
 1316  
                     .getGenericComponentType(), assigningType);
 1317  
 
 1318  
             // create array type from raw component type and return its class
 1319  1
             return Array.newInstance(rawComponentType, 0).getClass();
 1320  
         }
 1321  
 
 1322  
         // (hand-waving) this is not the method you're looking for
 1323  0
         if (type instanceof WildcardType) {
 1324  0
             return null;
 1325  
         }
 1326  
 
 1327  0
         throw new IllegalArgumentException("unknown type: " + type);
 1328  
     }
 1329  
 
 1330  
     /**
 1331  
      * Learn whether the specified type denotes an array type.
 1332  
      * @param type the type to be checked
 1333  
      * @return {@code true} if {@code type} is an array class or a {@link GenericArrayType}.
 1334  
      */
 1335  
     public static boolean isArrayType(final Type type) {
 1336  34
         return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
 1337  
     }
 1338  
 
 1339  
     /**
 1340  
      * Get the array component type of {@code type}.
 1341  
      * @param type the type to be checked
 1342  
      * @return component type or null if type is not an array type
 1343  
      */
 1344  
     public static Type getArrayComponentType(final Type type) {
 1345  30
         if (type instanceof Class<?>) {
 1346  18
             final Class<?> clazz = (Class<?>) type;
 1347  18
             return clazz.isArray() ? clazz.getComponentType() : null;
 1348  
         }
 1349  12
         if (type instanceof GenericArrayType) {
 1350  6
             return ((GenericArrayType) type).getGenericComponentType();
 1351  
         }
 1352  6
         return null;
 1353  
     }
 1354  
 
 1355  
     /**
 1356  
      * Get a type representing {@code type} with variable assignments "unrolled."
 1357  
      *
 1358  
      * @param typeArguments as from {@link TypeUtils#getTypeArguments(Type, Class)}
 1359  
      * @param type the type to unroll variable assignments for
 1360  
      * @return Type
 1361  
      * @since 3.2
 1362  
      */
 1363  
     public static Type unrollVariables(Map<TypeVariable<?>, Type> typeArguments, final Type type) {
 1364  9
         if (typeArguments == null) {
 1365  0
             typeArguments = Collections.<TypeVariable<?>, Type> emptyMap();
 1366  
         }
 1367  9
         if (containsTypeVariables(type)) {
 1368  3
             if (type instanceof TypeVariable<?>) {
 1369  3
                 return unrollVariables(typeArguments, typeArguments.get(type));
 1370  
             }
 1371  0
             if (type instanceof ParameterizedType) {
 1372  0
                 final ParameterizedType p = (ParameterizedType) type;
 1373  
                 final Map<TypeVariable<?>, Type> parameterizedTypeArguments;
 1374  0
                 if (p.getOwnerType() == null) {
 1375  0
                     parameterizedTypeArguments = typeArguments;
 1376  
                 } else {
 1377  0
                     parameterizedTypeArguments = new HashMap<TypeVariable<?>, Type>(typeArguments);
 1378  0
                     parameterizedTypeArguments.putAll(TypeUtils.getTypeArguments(p));
 1379  
                 }
 1380  0
                 final Type[] args = p.getActualTypeArguments();
 1381  0
                 for (int i = 0; i < args.length; i++) {
 1382  0
                     final Type unrolled = unrollVariables(parameterizedTypeArguments, args[i]);
 1383  0
                     if (unrolled != null) {
 1384  0
                         args[i] = unrolled;
 1385  
                     }
 1386  
                 }
 1387  0
                 return parameterizeWithOwner(p.getOwnerType(), (Class<?>) p.getRawType(), args);
 1388  
             }
 1389  0
             if (type instanceof WildcardType) {
 1390  0
                 final WildcardType wild = (WildcardType) type;
 1391  0
                 return wildcardType().withUpperBounds(unrollBounds(typeArguments, wild.getUpperBounds()))
 1392  
                     .withLowerBounds(unrollBounds(typeArguments, wild.getLowerBounds())).build();
 1393  
             }
 1394  
         }
 1395  6
         return type;
 1396  
     }
 1397  
 
 1398  
     /**
 1399  
      * Local helper method to unroll variables in a type bounds array.
 1400  
      * 
 1401  
      * @param typeArguments assignments {@link Map}
 1402  
      * @param bounds in which to expand variables
 1403  
      * @return {@code bounds} with any variables reassigned
 1404  
      * @since 3.2
 1405  
      */
 1406  
     private static Type[] unrollBounds(final Map<TypeVariable<?>, Type> typeArguments, final Type[] bounds) {
 1407  0
         Type[] result = bounds;
 1408  0
         int i = 0;
 1409  0
         for (; i < result.length; i++) {
 1410  0
             final Type unrolled = unrollVariables(typeArguments, result[i]);
 1411  0
             if (unrolled == null) {
 1412  0
                 result = ArrayUtils.remove(result, i--);
 1413  
             } else {
 1414  0
                 result[i] = unrolled;
 1415  
             }
 1416  
         }
 1417  0
         return result;
 1418  
     }
 1419  
 
 1420  
     /**
 1421  
      * Learn, recursively, whether any of the type parameters associated with {@code type} are bound to variables.
 1422  
      *
 1423  
      * @param type the type to check for type variables
 1424  
      * @return boolean
 1425  
      * @since 3.2
 1426  
      */
 1427  
     public static boolean containsTypeVariables(Type type) {
 1428  9
         if (type instanceof TypeVariable<?>) {
 1429  3
             return true;
 1430  
         }
 1431  6
         if (type instanceof Class<?>) {
 1432  6
             return ((Class<?>) type).getTypeParameters().length > 0;
 1433  
         }
 1434  0
         if (type instanceof ParameterizedType) {
 1435  0
             for (Type arg : ((ParameterizedType) type).getActualTypeArguments()) {
 1436  0
                 if (containsTypeVariables(arg)) {
 1437  0
                     return true;
 1438  
                 }
 1439  
             }
 1440  0
             return false;
 1441  
         }
 1442  0
         if (type instanceof WildcardType) {
 1443  0
             WildcardType wild = (WildcardType) type;
 1444  0
             return containsTypeVariables(TypeUtils.getImplicitLowerBounds(wild)[0])
 1445  
                 || containsTypeVariables(TypeUtils.getImplicitUpperBounds(wild)[0]);
 1446  
         }
 1447  0
         return false;
 1448  
     }
 1449  
 
 1450  
     /**
 1451  
      * Create a parameterized type instance.
 1452  
      *
 1453  
      * @param raw the raw class to create a parameterized type instance for
 1454  
      * @param typeArguments the types used for parameterization
 1455  
      * @return {@link ParameterizedType}
 1456  
      * @since 3.2
 1457  
      */
 1458  
     public static final ParameterizedType parameterize(final Class<?> raw, final Type... typeArguments) {
 1459  5
         return parameterizeWithOwner(null, raw, typeArguments);
 1460  
     }
 1461  
 
 1462  
     /**
 1463  
      * Create a parameterized type instance.
 1464  
      *
 1465  
      * @param raw the raw class to create a parameterized type instance for
 1466  
      * @param typeArgMappings the mapping used for parameterization
 1467  
      * @return {@link ParameterizedType}
 1468  
      * @since 3.2
 1469  
      */
 1470  
     public static final ParameterizedType parameterize(final Class<?> raw,
 1471  
         final Map<TypeVariable<?>, Type> typeArgMappings) {
 1472  0
         Validate.notNull(raw, "raw class is null");
 1473  0
         Validate.notNull(typeArgMappings, "typeArgMappings is null");
 1474  0
         return parameterizeWithOwner(null, raw, extractTypeArgumentsFrom(typeArgMappings, raw.getTypeParameters()));
 1475  
     }
 1476  
 
 1477  
     /**
 1478  
      * Create a parameterized type instance.
 1479  
      *
 1480  
      * @param owner the owning type
 1481  
      * @param raw the raw class to create a parameterized type instance for
 1482  
      * @param typeArguments the types used for parameterization
 1483  
      *
 1484  
      * @return {@link ParameterizedType}
 1485  
      * @since 3.2
 1486  
      */
 1487  
     public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> raw,
 1488  
         final Type... typeArguments) {
 1489  6
         Validate.notNull(raw, "raw class is null");
 1490  
         final Type useOwner;
 1491  6
         if (raw.getEnclosingClass() == null) {
 1492  5
             Validate.isTrue(owner == null, "no owner allowed for top-level %s", raw);
 1493  5
             useOwner = null;
 1494  1
         } else if (owner == null) {
 1495  0
             useOwner = raw.getEnclosingClass();
 1496  
         } else {
 1497  1
             Validate.isTrue(TypeUtils.isAssignable(owner, raw.getEnclosingClass()),
 1498  
                 "%s is invalid owner type for parameterized %s", owner, raw);
 1499  1
             useOwner = owner;
 1500  
         }
 1501  6
         Validate.noNullElements(typeArguments, "null type argument at index %s");
 1502  6
         Validate.isTrue(raw.getTypeParameters().length == typeArguments.length,
 1503  
             "invalid number of type parameters specified: expected %s, got %s", raw.getTypeParameters().length,
 1504  
             typeArguments.length);
 1505  
 
 1506  6
         return new ParameterizedTypeImpl(raw, useOwner, typeArguments);
 1507  
     }
 1508  
 
 1509  
     /**
 1510  
      * Create a parameterized type instance.
 1511  
      *
 1512  
      * @param owner the owning type
 1513  
      * @param raw the raw class to create a parameterized type instance for
 1514  
      * @param typeArgMappings the mapping used for parameterization
 1515  
      * @return {@link ParameterizedType}
 1516  
      * @since 3.2
 1517  
      */
 1518  
     public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> raw,
 1519  
         final Map<TypeVariable<?>, Type> typeArgMappings) {
 1520  0
         Validate.notNull(raw, "raw class is null");
 1521  0
         Validate.notNull(typeArgMappings, "typeArgMappings is null");
 1522  0
         return parameterizeWithOwner(owner, raw, extractTypeArgumentsFrom(typeArgMappings, raw.getTypeParameters()));
 1523  
     }
 1524  
 
 1525  
     /**
 1526  
      * Helper method to establish the formal parameters for a parameterized type.
 1527  
      * @param mappings map containing the assignements
 1528  
      * @param variables expected map keys
 1529  
      * @return array of map values corresponding to specified keys
 1530  
      */
 1531  
     private static Type[] extractTypeArgumentsFrom(Map<TypeVariable<?>, Type> mappings, TypeVariable<?>[] variables) {
 1532  0
         final Type[] result = new Type[variables.length];
 1533  0
         int index = 0;
 1534  0
         for (TypeVariable<?> var : variables) {
 1535  0
             Validate.isTrue(mappings.containsKey(var), "missing argument mapping for %s", toString(var));
 1536  0
             result[index++] = mappings.get(var);
 1537  
         }
 1538  0
         return result;
 1539  
     }
 1540  
 
 1541  
     /**
 1542  
      * Get a {@link WildcardTypeBuilder}.
 1543  
      * @return {@link WildcardTypeBuilder}
 1544  
      * @since 3.2
 1545  
      */
 1546  
     public static WildcardTypeBuilder wildcardType() {
 1547  3
         return new WildcardTypeBuilder();
 1548  
     }
 1549  
 
 1550  
     /**
 1551  
      * Create a generic array type instance.
 1552  
      *
 1553  
      * @param componentType the type of the elements of the array. For example the component type of {@code boolean[]}
 1554  
      *                      is {@code boolean}
 1555  
      * @return {@link GenericArrayType}
 1556  
      * @since 3.2
 1557  
      */
 1558  
     public static GenericArrayType genericArrayType(final Type componentType) {
 1559  1
         return new GenericArrayTypeImpl(Validate.notNull(componentType, "componentType is null"));
 1560  
     }
 1561  
 
 1562  
     /**
 1563  
      * Check equality of types.
 1564  
      *
 1565  
      * @param t1 the first type
 1566  
      * @param t2 the second type
 1567  
      * @return boolean
 1568  
      * @since 3.2
 1569  
      */
 1570  
     @SuppressWarnings( "deprecation" )  // ObjectUtils.equals(Object, Object) has been deprecated in 3.2
 1571  
     public static boolean equals(Type t1, Type t2) {
 1572  26
         if (ObjectUtils.equals(t1, t2)) {
 1573  25
             return true;
 1574  
         }
 1575  1
         if (t1 instanceof ParameterizedType) {
 1576  0
             return equals((ParameterizedType) t1, t2);
 1577  
         }
 1578  1
         if (t1 instanceof GenericArrayType) {
 1579  0
             return equals((GenericArrayType) t1, t2);
 1580  
         }
 1581  1
         if (t1 instanceof WildcardType) {
 1582  0
             return equals((WildcardType) t1, t2);
 1583  
         }
 1584  1
         return false;
 1585  
     }
 1586  
 
 1587  
     /**
 1588  
      * Learn whether {@code t} equals {@code p}.
 1589  
      * @param p LHS
 1590  
      * @param t RHS
 1591  
      * @return boolean
 1592  
      * @since 3.2
 1593  
      */
 1594  
     private static boolean equals(ParameterizedType p, Type t) {
 1595  2
         if (t instanceof ParameterizedType) {
 1596  2
             final ParameterizedType other = (ParameterizedType) t;
 1597  2
             if (equals(p.getRawType(), other.getRawType()) && equals(p.getOwnerType(), other.getOwnerType())) {
 1598  2
                 return equals(p.getActualTypeArguments(), other.getActualTypeArguments());
 1599  
             }
 1600  
         }
 1601  0
         return false;
 1602  
     }
 1603  
 
 1604  
     /**
 1605  
      * Learn whether {@code t} equals {@code a}.
 1606  
      * @param a LHS
 1607  
      * @param t RHS
 1608  
      * @return boolean
 1609  
      * @since 3.2
 1610  
      */
 1611  
     private static boolean equals(GenericArrayType a, Type t) {
 1612  0
         return t instanceof GenericArrayType
 1613  
             && equals(a.getGenericComponentType(), ((GenericArrayType) t).getGenericComponentType());
 1614  
     }
 1615  
 
 1616  
     /**
 1617  
      * Learn whether {@code t} equals {@code w}.
 1618  
      * @param w LHS
 1619  
      * @param t RHS
 1620  
      * @return boolean
 1621  
      * @since 3.2
 1622  
      */
 1623  
     private static boolean equals(WildcardType w, Type t) {
 1624  0
         if (t instanceof WildcardType) {
 1625  0
             final WildcardType other = (WildcardType) t;
 1626  0
             return equals(w.getLowerBounds(), other.getLowerBounds())
 1627  
                 && equals(TypeUtils.getImplicitUpperBounds(w), TypeUtils.getImplicitUpperBounds(other));
 1628  
         }
 1629  0
         return true;
 1630  
     }
 1631  
 
 1632  
     /**
 1633  
      * Learn whether {@code t1} equals {@code t2}.
 1634  
      * @param t1 LHS
 1635  
      * @param t2 RHS
 1636  
      * @return boolean
 1637  
      * @since 3.2
 1638  
      */
 1639  
     private static boolean equals(Type[] t1, Type[] t2) {
 1640  2
         if (t1.length == t2.length) {
 1641  4
             for (int i = 0; i < t1.length; i++) {
 1642  2
                 if (!equals(t1[i], t2[i])) {
 1643  0
                     return false;
 1644  
                 }
 1645  
             }
 1646  2
             return true;
 1647  
         }
 1648  0
         return false;
 1649  
     }
 1650  
 
 1651  
     /**
 1652  
      * Present a given type as a Java-esque String.
 1653  
      *
 1654  
      * @param type the type to create a String representation for, not {@code null}
 1655  
      * @return String
 1656  
      * @since 3.2
 1657  
      */
 1658  
     public static String toString(Type type) {
 1659  21
         Validate.notNull(type);
 1660  21
         if (type instanceof Class<?>) {
 1661  12
             return classToString((Class<?>) type);
 1662  
         }
 1663  9
         if (type instanceof ParameterizedType) {
 1664  7
             return parameterizedTypeToString((ParameterizedType) type);
 1665  
         }
 1666  2
         if (type instanceof WildcardType) {
 1667  1
             return wildcardTypeToString((WildcardType) type);
 1668  
         }
 1669  1
         if (type instanceof TypeVariable<?>) {
 1670  0
             return typeVariableToString((TypeVariable<?>) type);
 1671  
         }
 1672  1
         if (type instanceof GenericArrayType) {
 1673  1
             return genericArrayTypeToString((GenericArrayType) type);
 1674  
         }
 1675  0
         throw new IllegalArgumentException(ObjectUtils.identityToString(type));
 1676  
     }
 1677  
 
 1678  
     /**
 1679  
      * Format a {@link TypeVariable} including its {@link GenericDeclaration}.
 1680  
      *
 1681  
      * @param var the type variable to create a String representation for, not {@code null}
 1682  
      * @return String
 1683  
      * @since 3.2
 1684  
      */
 1685  
     public static String toLongString(TypeVariable<?> var) {
 1686  12
         Validate.notNull(var, "var is null");
 1687  12
         final StringBuilder buf = new StringBuilder();
 1688  12
         final GenericDeclaration d = ((TypeVariable<?>) var).getGenericDeclaration();
 1689  12
         if (d instanceof Class<?>) {
 1690  12
             Class<?> c = (Class<?>) d;
 1691  
             while (true) {
 1692  12
                 if (c.getEnclosingClass() == null) {
 1693  12
                     buf.insert(0, c.getName());
 1694  12
                     break;
 1695  
                 }
 1696  0
                 buf.insert(0, c.getSimpleName()).insert(0, '.');
 1697  0
                 c = c.getEnclosingClass();
 1698  
             }
 1699  12
         } else if (d instanceof Type) {// not possible as of now
 1700  0
             buf.append(toString((Type) d));
 1701  
         } else {
 1702  0
             buf.append(d);
 1703  
         }
 1704  12
         return buf.append(':').append(typeVariableToString(var)).toString();
 1705  
     }
 1706  
 
 1707  
     /**
 1708  
      * Wrap the specified {@link Type} in a {@link Typed} wrapper.
 1709  
      *
 1710  
      * @param <T> inferred generic type
 1711  
      * @param type to wrap
 1712  
      * @return Typed&lt;T&gt;
 1713  
      * @since 3.2
 1714  
      */
 1715  
     public static <T> Typed<T> wrap(final Type type) {
 1716  2
         return new Typed<T>() {
 1717  
             @Override
 1718  
             public Type getType() {
 1719  2
                 return type;
 1720  
             }
 1721  
         };
 1722  
     }
 1723  
 
 1724  
     /**
 1725  
      * Wrap the specified {@link Class} in a {@link Typed} wrapper.
 1726  
      *
 1727  
      * @param <T> generic type
 1728  
      * @param type to wrap
 1729  
      * @return Typed&lt;T&gt;
 1730  
      * @since 3.2
 1731  
      */
 1732  
     public static <T> Typed<T> wrap(final Class<T> type) {
 1733  1
         return TypeUtils.<T> wrap((Type) type);
 1734  
     }
 1735  
 
 1736  
     /**
 1737  
      * Format a {@link Class} as a {@link String}.
 1738  
      * @param c {@code Class} to format
 1739  
      * @return String
 1740  
      * @since 3.2
 1741  
      */
 1742  
     private static String classToString(Class<?> c) {
 1743  12
         final StringBuilder buf = new StringBuilder();
 1744  
 
 1745  12
         if (c.getEnclosingClass() != null) {
 1746  0
             buf.append(classToString(c.getEnclosingClass())).append('.').append(c.getSimpleName());
 1747  
         } else {
 1748  12
             buf.append(c.getName());
 1749  
         }
 1750  12
         if (c.getTypeParameters().length > 0) {
 1751  0
             buf.append('<');
 1752  0
             appendAllTo(buf, ", ", c.getTypeParameters());
 1753  0
             buf.append('>');
 1754  
         }
 1755  12
         return buf.toString();
 1756  
     }
 1757  
 
 1758  
     /**
 1759  
      * Format a {@link TypeVariable} as a {@link String}.
 1760  
      * @param v {@code TypeVariable} to format
 1761  
      * @return String
 1762  
      * @since 3.2
 1763  
      */
 1764  
     private static String typeVariableToString(TypeVariable<?> v) {
 1765  12
         final StringBuilder buf = new StringBuilder(v.getName());
 1766  12
         final Type[] bounds = v.getBounds();
 1767  12
         if (bounds.length > 0 && !(bounds.length == 1 && Object.class.equals(bounds[0]))) {
 1768  0
             buf.append(" extends ");
 1769  0
             appendAllTo(buf, " & ", v.getBounds());
 1770  
         }
 1771  12
         return buf.toString();
 1772  
     }
 1773  
 
 1774  
     /**
 1775  
      * Format a {@link ParameterizedType} as a {@link String}.
 1776  
      * @param p {@code ParameterizedType} to format
 1777  
      * @return String
 1778  
      * @since 3.2
 1779  
      */
 1780  
     private static String parameterizedTypeToString(ParameterizedType p) {
 1781  7
         final StringBuilder buf = new StringBuilder();
 1782  
 
 1783  7
         final Type useOwner = p.getOwnerType();
 1784  7
         final Class<?> raw = (Class<?>) p.getRawType();
 1785  7
         final Type[] typeArguments = p.getActualTypeArguments();
 1786  7
         if (useOwner == null) {
 1787  7
             buf.append(raw.getName());
 1788  
         } else {
 1789  0
             if (useOwner instanceof Class<?>) {
 1790  0
                 buf.append(((Class<?>) useOwner).getName());
 1791  
             } else {
 1792  0
                 buf.append(useOwner.toString());
 1793  
             }
 1794  0
             buf.append('.').append(raw.getSimpleName());
 1795  
         }
 1796  
 
 1797  7
         appendAllTo(buf.append('<'), ", ", typeArguments).append('>');
 1798  7
         return buf.toString();
 1799  
     }
 1800  
 
 1801  
     /**
 1802  
      * Format a {@link WildcardType} as a {@link String}.
 1803  
      * @param w {@code WildcardType} to format
 1804  
      * @return String
 1805  
      * @since 3.2
 1806  
      */
 1807  
     private static String wildcardTypeToString(WildcardType w) {
 1808  1
         final StringBuilder buf = new StringBuilder().append('?');
 1809  1
         final Type[] lowerBounds = w.getLowerBounds();
 1810  1
         final Type[] upperBounds = w.getUpperBounds();
 1811  1
         if (lowerBounds.length > 0) {
 1812  0
             appendAllTo(buf.append(" super "), " & ", lowerBounds);
 1813  1
         } else if (!(upperBounds.length == 1 && Object.class.equals(upperBounds[0]))) {
 1814  1
             appendAllTo(buf.append(" extends "), " & ", upperBounds);
 1815  
         }
 1816  1
         return buf.toString();
 1817  
     }
 1818  
 
 1819  
     /**
 1820  
      * Format a {@link GenericArrayType} as a {@link String}.
 1821  
      * @param g {@code GenericArrayType} to format
 1822  
      * @return String
 1823  
      * @since 3.2
 1824  
      */
 1825  
     private static String genericArrayTypeToString(GenericArrayType g) {
 1826  1
         return String.format("%s[]", toString(g.getGenericComponentType()));
 1827  
     }
 1828  
 
 1829  
     /**
 1830  
      * Append {@code types} to @{code buf} with separator {@code sep}.
 1831  
      * @param buf destination
 1832  
      * @param sep separator
 1833  
      * @param types to append
 1834  
      * @return {@code buf}
 1835  
      * @since 3.2
 1836  
      */
 1837  
     private static StringBuilder appendAllTo(StringBuilder buf, String sep, Type... types) {
 1838  8
         Validate.notEmpty(Validate.noNullElements(types));
 1839  8
         if (types.length > 0) {
 1840  8
             buf.append(toString(types[0]));
 1841  8
             for (int i = 1; i < types.length; i++) {
 1842  0
                 buf.append(sep).append(toString(types[i]));
 1843  
             }
 1844  
         }
 1845  8
         return buf;
 1846  
     }
 1847  
 
 1848  
 }