Coverage Report - org.apache.commons.lang3.reflect.TypeUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
TypeUtils
71%
203/283
61%
173/282
8.857
 
 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.ParameterizedType;
 22  
 import java.lang.reflect.Type;
 23  
 import java.lang.reflect.TypeVariable;
 24  
 import java.lang.reflect.WildcardType;
 25  
 import java.util.Arrays;
 26  
 import java.util.HashMap;
 27  
 import java.util.HashSet;
 28  
 import java.util.List;
 29  
 import java.util.Map;
 30  
 import java.util.Set;
 31  
 
 32  
 import org.apache.commons.lang3.ClassUtils;
 33  
 
 34  
 /**
 35  
  * <p> Utility methods focusing on type inspection, particularly with regard to
 36  
  * generics. </p>
 37  
  *
 38  
  * @since 3.0
 39  
  * @version $Id: TypeUtils.java 1436770 2013-01-22 07:09:45Z ggregory $
 40  
  */
 41  
 public class TypeUtils {
 42  
 
 43  
     /**
 44  
      * <p> TypeUtils instances should NOT be constructed in standard
 45  
      * programming. Instead, the class should be used as
 46  
      * <code>TypeUtils.isAssignable(cls, toClass)</code>. </p> <p> This
 47  
      * constructor is public to permit tools that require a JavaBean instance to
 48  
      * operate. </p>
 49  
      */
 50  
     public TypeUtils() {
 51  0
         super();
 52  0
     }
 53  
 
 54  
     /**
 55  
      * <p> Checks if the subject type may be implicitly cast to the target type
 56  
      * following the Java generics rules. If both types are {@link Class}
 57  
      * objects, the method returns the result of
 58  
      * {@link ClassUtils#isAssignable(Class, Class)}. </p>
 59  
      *
 60  
      * @param type the subject type to be assigned to the target type
 61  
      * @param toType the target type
 62  
      * @return <code>true</code> if <code>type</code> is assignable to <code>toType</code>.
 63  
      */
 64  
     public static boolean isAssignable(final Type type, final Type toType) {
 65  168
         return isAssignable(type, toType, null);
 66  
     }
 67  
 
 68  
     /**
 69  
      * <p> Checks if the subject type may be implicitly cast to the target type
 70  
      * following the Java generics rules. </p>
 71  
      *
 72  
      * @param type the subject type to be assigned to the target type
 73  
      * @param toType the target type
 74  
      * @param typeVarAssigns optional map of type variable assignments
 75  
      * @return <code>true</code> if <code>type</code> is assignable to <code>toType</code>.
 76  
      */
 77  
     private static boolean isAssignable(final Type type, final Type toType,
 78  
             final Map<TypeVariable<?>, Type> typeVarAssigns) {
 79  334
         if (toType == null || toType instanceof Class<?>) {
 80  141
             return isAssignable(type, (Class<?>) toType);
 81  
         }
 82  
 
 83  193
         if (toType instanceof ParameterizedType) {
 84  106
             return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
 85  
         }
 86  
 
 87  87
         if (toType instanceof GenericArrayType) {
 88  43
             return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
 89  
         }
 90  
 
 91  44
         if (toType instanceof WildcardType) {
 92  44
             return isAssignable(type, (WildcardType) toType, typeVarAssigns);
 93  
         }
 94  
 
 95  
         // *
 96  0
         if (toType instanceof TypeVariable<?>) {
 97  0
             return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
 98  
         }
 99  
         // */
 100  
 
 101  0
         throw new IllegalStateException("found an unhandled type: " + toType);
 102  
     }
 103  
 
 104  
     /**
 105  
      * <p> Checks if the subject type may be implicitly cast to the target class
 106  
      * following the Java generics rules. </p>
 107  
      *
 108  
      * @param type the subject type to be assigned to the target type
 109  
      * @param toClass the target class
 110  
      * @return true if <code>type</code> is assignable to <code>toClass</code>.
 111  
      */
 112  
     private static boolean isAssignable(final Type type, final Class<?> toClass) {
 113  451
         if (type == null) {
 114  
             // consistency with ClassUtils.isAssignable() behavior
 115  42
             return toClass == null || !toClass.isPrimitive();
 116  
         }
 117  
 
 118  
         // only a null type can be assigned to null type which
 119  
         // would have cause the previous to return true
 120  409
         if (toClass == null) {
 121  8
             return false;
 122  
         }
 123  
 
 124  
         // all types are assignable to themselves
 125  401
         if (toClass.equals(type)) {
 126  276
             return true;
 127  
         }
 128  
 
 129  125
         if (type instanceof Class<?>) {
 130  
             // just comparing two classes
 131  107
             return ClassUtils.isAssignable((Class<?>) type, toClass);
 132  
         }
 133  
 
 134  18
         if (type instanceof ParameterizedType) {
 135  
             // only have to compare the raw type to the class
 136  12
             return isAssignable(getRawType((ParameterizedType) type), toClass);
 137  
         }
 138  
 
 139  
         // *
 140  6
         if (type instanceof TypeVariable<?>) {
 141  
             // if any of the bounds are assignable to the class, then the
 142  
             // type is assignable to the class.
 143  0
             for (final Type bound : ((TypeVariable<?>) type).getBounds()) {
 144  0
                 if (isAssignable(bound, toClass)) {
 145  0
                     return true;
 146  
                 }
 147  
             }
 148  
 
 149  0
             return false;
 150  
         }
 151  
 
 152  
         // the only classes to which a generic array type can be assigned
 153  
         // are class Object and array classes
 154  6
         if (type instanceof GenericArrayType) {
 155  6
             return toClass.equals(Object.class)
 156  
                     || toClass.isArray()
 157  
                     && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass
 158  
                             .getComponentType());
 159  
         }
 160  
 
 161  
         // wildcard types are not assignable to a class (though one would think
 162  
         // "? super Object" would be assignable to Object)
 163  0
         if (type instanceof WildcardType) {
 164  0
             return false;
 165  
         }
 166  
 
 167  0
         throw new IllegalStateException("found an unhandled type: " + type);
 168  
     }
 169  
 
 170  
     /**
 171  
      * <p> Checks if the subject type may be implicitly cast to the target
 172  
      * parameterized type following the Java generics rules. </p>
 173  
      *
 174  
      * @param type the subject type to be assigned to the target type
 175  
      * @param toParameterizedType the target parameterized type
 176  
      * @param typeVarAssigns a map with type variables
 177  
      * @return true if <code>type</code> is assignable to <code>toType</code>.
 178  
      */
 179  
     private static boolean isAssignable(final Type type, final ParameterizedType toParameterizedType,
 180  
             final Map<TypeVariable<?>, Type> typeVarAssigns) {
 181  106
         if (type == null) {
 182  0
             return true;
 183  
         }
 184  
 
 185  
         // only a null type can be assigned to null type which
 186  
         // would have cause the previous to return true
 187  106
         if (toParameterizedType == null) {
 188  0
             return false;
 189  
         }
 190  
 
 191  
         // all types are assignable to themselves
 192  106
         if (toParameterizedType.equals(type)) {
 193  6
             return true;
 194  
         }
 195  
 
 196  
         // get the target type's raw type
 197  100
         final Class<?> toClass = getRawType(toParameterizedType);
 198  
         // get the subject type's type arguments including owner type arguments
 199  
         // and supertype arguments up to and including the target class.
 200  100
         final Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
 201  
 
 202  
         // null means the two types are not compatible
 203  100
         if (fromTypeVarAssigns == null) {
 204  0
             return false;
 205  
         }
 206  
 
 207  
         // compatible types, but there's no type arguments. this is equivalent
 208  
         // to comparing Map< ?, ? > to Map, and raw types are always assignable
 209  
         // to parameterized types.
 210  100
         if (fromTypeVarAssigns.isEmpty()) {
 211  12
             return true;
 212  
         }
 213  
 
 214  
         // get the target type's type arguments including owner type arguments
 215  88
         final Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType,
 216  
                 toClass, typeVarAssigns);
 217  
 
 218  
         // now to check each type argument
 219  88
         for (final TypeVariable<?> var : toTypeVarAssigns.keySet()) {
 220  97
             final Type toTypeArg = unrollVariableAssignments(var, toTypeVarAssigns);
 221  97
             final Type fromTypeArg = unrollVariableAssignments(var, fromTypeVarAssigns);
 222  
 
 223  
             // parameters must either be absent from the subject type, within
 224  
             // the bounds of the wildcard type, or be an exact match to the
 225  
             // parameters of the target type.
 226  97
             if (fromTypeArg != null
 227  
                     && !toTypeArg.equals(fromTypeArg)
 228  
                     && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg,
 229  
                             typeVarAssigns))) {
 230  49
                 return false;
 231  
             }
 232  48
         }
 233  
 
 234  39
         return true;
 235  
     }
 236  
 
 237  
     private static Type unrollVariableAssignments(TypeVariable<?> var, final Map<TypeVariable<?>, Type> typeVarAssigns) {
 238  
         Type result;
 239  
         do {
 240  198
             result = typeVarAssigns.get(var);
 241  198
             if (result instanceof TypeVariable<?> && !result.equals(var)) {
 242  4
                 var = (TypeVariable<?>) result;
 243  4
                 continue;
 244  
             }
 245  
             break;
 246  
         } while (true);
 247  194
         return result;
 248  
     }
 249  
 
 250  
     /**
 251  
      * <p> Checks if the subject type may be implicitly cast to the target
 252  
      * generic array type following the Java generics rules. </p>
 253  
      *
 254  
      * @param type the subject type to be assigned to the target type
 255  
      * @param toGenericArrayType the target generic array type
 256  
      * @param typeVarAssigns a map with type variables
 257  
      * @return true if <code>type</code> is assignable to
 258  
      * <code>toGenericArrayType</code>.
 259  
      */
 260  
     private static boolean isAssignable(final Type type, final GenericArrayType toGenericArrayType,
 261  
             final Map<TypeVariable<?>, Type> typeVarAssigns) {
 262  43
         if (type == null) {
 263  0
             return true;
 264  
         }
 265  
 
 266  
         // only a null type can be assigned to null type which
 267  
         // would have cause the previous to return true
 268  43
         if (toGenericArrayType == null) {
 269  0
             return false;
 270  
         }
 271  
 
 272  
         // all types are assignable to themselves
 273  43
         if (toGenericArrayType.equals(type)) {
 274  6
             return true;
 275  
         }
 276  
 
 277  37
         final Type toComponentType = toGenericArrayType.getGenericComponentType();
 278  
 
 279  37
         if (type instanceof Class<?>) {
 280  7
             final Class<?> cls = (Class<?>) type;
 281  
 
 282  
             // compare the component types
 283  7
             return cls.isArray()
 284  
                     && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
 285  
         }
 286  
 
 287  30
         if (type instanceof GenericArrayType) {
 288  
             // compare the component types
 289  30
             return isAssignable(((GenericArrayType) type).getGenericComponentType(),
 290  
                     toComponentType, typeVarAssigns);
 291  
         }
 292  
 
 293  0
         if (type instanceof WildcardType) {
 294  
             // so long as one of the upper bounds is assignable, it's good
 295  0
             for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
 296  0
                 if (isAssignable(bound, toGenericArrayType)) {
 297  0
                     return true;
 298  
                 }
 299  
             }
 300  
 
 301  0
             return false;
 302  
         }
 303  
 
 304  0
         if (type instanceof TypeVariable<?>) {
 305  
             // probably should remove the following logic and just return false.
 306  
             // type variables cannot specify arrays as bounds.
 307  0
             for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
 308  0
                 if (isAssignable(bound, toGenericArrayType)) {
 309  0
                     return true;
 310  
                 }
 311  
             }
 312  
 
 313  0
             return false;
 314  
         }
 315  
 
 316  0
         if (type instanceof ParameterizedType) {
 317  
             // the raw type of a parameterized type is never an array or
 318  
             // generic array, otherwise the declaration would look like this:
 319  
             // Collection[]< ? extends String > collection;
 320  0
             return false;
 321  
         }
 322  
 
 323  0
         throw new IllegalStateException("found an unhandled type: " + type);
 324  
     }
 325  
 
 326  
     /**
 327  
      * <p> Checks if the subject type may be implicitly cast to the target
 328  
      * wildcard type following the Java generics rules. </p>
 329  
      *
 330  
      * @param type the subject type to be assigned to the target type
 331  
      * @param toWildcardType the target wildcard type
 332  
      * @param typeVarAssigns a map with type variables
 333  
      * @return true if <code>type</code> is assignable to
 334  
      * <code>toWildcardType</code>.
 335  
      */
 336  
     private static boolean isAssignable(final Type type, final WildcardType toWildcardType,
 337  
             final Map<TypeVariable<?>, Type> typeVarAssigns) {
 338  44
         if (type == null) {
 339  0
             return true;
 340  
         }
 341  
 
 342  
         // only a null type can be assigned to null type which
 343  
         // would have cause the previous to return true
 344  44
         if (toWildcardType == null) {
 345  0
             return false;
 346  
         }
 347  
 
 348  
         // all types are assignable to themselves
 349  44
         if (toWildcardType.equals(type)) {
 350  0
             return true;
 351  
         }
 352  
 
 353  44
         final Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
 354  44
         final Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
 355  
 
 356  44
         if (type instanceof WildcardType) {
 357  24
             final WildcardType wildcardType = (WildcardType) type;
 358  24
             final Type[] upperBounds = getImplicitUpperBounds(wildcardType);
 359  24
             final Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
 360  
 
 361  42
             for (Type toBound : toUpperBounds) {
 362  
                 // if there are assignments for unresolved type variables,
 363  
                 // now's the time to substitute them.
 364  24
                 toBound = substituteTypeVariables(toBound, typeVarAssigns);
 365  
 
 366  
                 // each upper bound of the subject type has to be assignable to
 367  
                 // each
 368  
                 // upper bound of the target type
 369  42
                 for (final Type bound : upperBounds) {
 370  24
                     if (!isAssignable(bound, toBound, typeVarAssigns)) {
 371  6
                         return false;
 372  
                     }
 373  
                 }
 374  
             }
 375  
 
 376  26
             for (Type toBound : toLowerBounds) {
 377  
                 // if there are assignments for unresolved type variables,
 378  
                 // now's the time to substitute them.
 379  18
                 toBound = substituteTypeVariables(toBound, typeVarAssigns);
 380  
 
 381  
                 // each lower bound of the target type has to be assignable to
 382  
                 // each
 383  
                 // lower bound of the subject type
 384  26
                 for (final Type bound : lowerBounds) {
 385  18
                     if (!isAssignable(toBound, bound, typeVarAssigns)) {
 386  10
                         return false;
 387  
                     }
 388  
                 }
 389  
             }
 390  
 
 391  8
             return true;
 392  
         }
 393  
 
 394  38
         for (final Type toBound : toUpperBounds) {
 395  
             // if there are assignments for unresolved type variables,
 396  
             // now's the time to substitute them.
 397  20
             if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns),
 398  
                     typeVarAssigns)) {
 399  2
                 return false;
 400  
             }
 401  
         }
 402  
 
 403  34
         for (final Type toBound : toLowerBounds) {
 404  
             // if there are assignments for unresolved type variables,
 405  
             // now's the time to substitute them.
 406  18
             if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type,
 407  
                     typeVarAssigns)) {
 408  2
                 return false;
 409  
             }
 410  
         }
 411  
 
 412  16
         return true;
 413  
     }
 414  
 
 415  
     /**
 416  
      * <p> Checks if the subject type may be implicitly cast to the target type
 417  
      * variable following the Java generics rules. </p>
 418  
      *
 419  
      * @param type the subject type to be assigned to the target type
 420  
      * @param toTypeVariable the target type variable
 421  
      * @param typeVarAssigns a map with type variables
 422  
      * @return true if <code>type</code> is assignable to
 423  
      * <code>toTypeVariable</code>.
 424  
      */
 425  
     private static boolean isAssignable(final Type type, final TypeVariable<?> toTypeVariable,
 426  
             final Map<TypeVariable<?>, Type> typeVarAssigns) {
 427  0
         if (type == null) {
 428  0
             return true;
 429  
         }
 430  
 
 431  
         // only a null type can be assigned to null type which
 432  
         // would have cause the previous to return true
 433  0
         if (toTypeVariable == null) {
 434  0
             return false;
 435  
         }
 436  
 
 437  
         // all types are assignable to themselves
 438  0
         if (toTypeVariable.equals(type)) {
 439  0
             return true;
 440  
         }
 441  
 
 442  0
         if (type instanceof TypeVariable<?>) {
 443  
             // a type variable is assignable to another type variable, if
 444  
             // and only if the former is the latter, extends the latter, or
 445  
             // is otherwise a descendant of the latter.
 446  0
             final Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
 447  
 
 448  0
             for (final Type bound : bounds) {
 449  0
                 if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
 450  0
                     return true;
 451  
                 }
 452  
             }
 453  
         }
 454  
 
 455  0
         if (type instanceof Class<?> || type instanceof ParameterizedType
 456  
                 || type instanceof GenericArrayType || type instanceof WildcardType) {
 457  0
             return false;
 458  
         }
 459  
 
 460  0
         throw new IllegalStateException("found an unhandled type: " + type);
 461  
     }
 462  
 
 463  
     /**
 464  
      * <p> </p>
 465  
      *
 466  
      * @param type the type to be replaced
 467  
      * @param typeVarAssigns the map with type variables
 468  
      * @return the replaced type
 469  
      * @throws IllegalArgumentException if the type cannot be substituted
 470  
      */
 471  
     private static Type substituteTypeVariables(final Type type, final Map<TypeVariable<?>, Type> typeVarAssigns) {
 472  83
         if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
 473  2
             final Type replacementType = typeVarAssigns.get(type);
 474  
 
 475  2
             if (replacementType == null) {
 476  0
                 throw new IllegalArgumentException("missing assignment type for type variable "
 477  
                         + type);
 478  
             }
 479  
 
 480  2
             return replacementType;
 481  
         }
 482  
 
 483  81
         return type;
 484  
     }
 485  
 
 486  
     /**
 487  
      * <p> Retrieves all the type arguments for this parameterized type
 488  
      * including owner hierarchy arguments such as <code>
 489  
      * Outer<K,V>.Inner<T>.DeepInner<E></code> . The arguments are returned in a
 490  
      * {@link Map} specifying the argument type for each {@link TypeVariable}.
 491  
      * </p>
 492  
      *
 493  
      * @param type specifies the subject parameterized type from which to
 494  
      * harvest the parameters.
 495  
      * @return a map of the type arguments to their respective type variables.
 496  
      */
 497  
     public static Map<TypeVariable<?>, Type> getTypeArguments(final ParameterizedType type) {
 498  0
         return getTypeArguments(type, getRawType(type), null);
 499  
     }
 500  
 
 501  
     /**
 502  
      * <p> Gets the type arguments of a class/interface based on a subtype. For
 503  
      * instance, this method will determine that both of the parameters for the
 504  
      * interface {@link Map} are {@link Object} for the subtype
 505  
      * {@link java.util.Properties Properties} even though the subtype does not
 506  
      * directly implement the <code>Map</code> interface. <p> </p> This method
 507  
      * returns <code>null</code> if <code>type</code> is not assignable to
 508  
      * <code>toClass</code>. It returns an empty map if none of the classes or
 509  
      * interfaces in its inheritance hierarchy specify any type arguments. </p>
 510  
      * <p> A side-effect of this method is that it also retrieves the type
 511  
      * arguments for the classes and interfaces that are part of the hierarchy
 512  
      * between <code>type</code> and <code>toClass</code>. So with the above
 513  
      * example, this method will also determine that the type arguments for
 514  
      * {@link java.util.Hashtable Hashtable} are also both <code>Object</code>.
 515  
      * In cases where the interface specified by <code>toClass</code> is
 516  
      * (indirectly) implemented more than once (e.g. where <code>toClass</code>
 517  
      * specifies the interface {@link java.lang.Iterable Iterable} and
 518  
      * <code>type</code> specifies a parameterized type that implements both
 519  
      * {@link java.util.Set Set} and {@link java.util.Collection Collection}),
 520  
      * this method will look at the inheritance hierarchy of only one of the
 521  
      * implementations/subclasses; the first interface encountered that isn't a
 522  
      * subinterface to one of the others in the <code>type</code> to
 523  
      * <code>toClass</code> hierarchy. </p>
 524  
      *
 525  
      * @param type the type from which to determine the type parameters of
 526  
      * <code>toClass</code>
 527  
      * @param toClass the class whose type parameters are to be determined based
 528  
      * on the subtype <code>type</code>
 529  
      * @return a map of the type assignments for the type variables in each type
 530  
      * in the inheritance hierarchy from <code>type</code> to
 531  
      * <code>toClass</code> inclusive.
 532  
      */
 533  
     public static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass) {
 534  10
         return getTypeArguments(type, toClass, null);
 535  
     }
 536  
 
 537  
     /**
 538  
      * <p> Return a map of the type arguments of <code>type</code> in the context of <code>toClass</code>. </p>
 539  
      *
 540  
      * @param type the type in question
 541  
      * @param toClass the class
 542  
      * @param subtypeVarAssigns a map with type variables
 543  
      * @return the map with type arguments
 544  
      */
 545  
     private static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass,
 546  
             final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
 547  155
         if (type instanceof Class<?>) {
 548  43
             return getTypeArguments((Class<?>) type, toClass, subtypeVarAssigns);
 549  
         }
 550  
 
 551  112
         if (type instanceof ParameterizedType) {
 552  112
             return getTypeArguments((ParameterizedType) type, toClass, subtypeVarAssigns);
 553  
         }
 554  
 
 555  0
         if (type instanceof GenericArrayType) {
 556  0
             return getTypeArguments(((GenericArrayType) type).getGenericComponentType(), toClass
 557  
                     .isArray() ? toClass.getComponentType() : toClass, subtypeVarAssigns);
 558  
         }
 559  
 
 560  
         // since wildcard types are not assignable to classes, should this just
 561  
         // return null?
 562  0
         if (type instanceof WildcardType) {
 563  0
             for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
 564  
                 // find the first bound that is assignable to the target class
 565  0
                 if (isAssignable(bound, toClass)) {
 566  0
                     return getTypeArguments(bound, toClass, subtypeVarAssigns);
 567  
                 }
 568  
             }
 569  
 
 570  0
             return null;
 571  
         }
 572  
 
 573  
         // *
 574  0
         if (type instanceof TypeVariable<?>) {
 575  0
             for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
 576  
                 // find the first bound that is assignable to the target class
 577  0
                 if (isAssignable(bound, toClass)) {
 578  0
                     return getTypeArguments(bound, toClass, subtypeVarAssigns);
 579  
                 }
 580  
             }
 581  
 
 582  0
             return null;
 583  
         }
 584  
         // */
 585  
 
 586  0
         throw new IllegalStateException("found an unhandled type: " + type);
 587  
     }
 588  
 
 589  
     /**
 590  
      * <p> Return a map of the type arguments of a parameterized type in the context of <code>toClass</code>. </p>
 591  
      *
 592  
      * @param parameterizedType the parameterized type
 593  
      * @param toClass the class
 594  
      * @param subtypeVarAssigns a map with type variables
 595  
      * @return the map with type arguments
 596  
      */
 597  
     private static Map<TypeVariable<?>, Type> getTypeArguments(
 598  
             final ParameterizedType parameterizedType, final Class<?> toClass,
 599  
             final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
 600  214
         final Class<?> cls = getRawType(parameterizedType);
 601  
 
 602  
         // make sure they're assignable
 603  214
         if (!isAssignable(cls, toClass)) {
 604  0
             return null;
 605  
         }
 606  
 
 607  214
         final Type ownerType = parameterizedType.getOwnerType();
 608  
         Map<TypeVariable<?>, Type> typeVarAssigns;
 609  
 
 610  214
         if (ownerType instanceof ParameterizedType) {
 611  
             // get the owner type arguments first
 612  13
             final ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
 613  13
             typeVarAssigns = getTypeArguments(parameterizedOwnerType,
 614  
                     getRawType(parameterizedOwnerType), subtypeVarAssigns);
 615  13
         } else {
 616  
             // no owner, prep the type variable assignments map
 617  201
             typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
 618  
                     : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
 619  
         }
 620  
 
 621  
         // get the subject parameterized type's arguments
 622  214
         final Type[] typeArgs = parameterizedType.getActualTypeArguments();
 623  
         // and get the corresponding type variables from the raw class
 624  214
         final TypeVariable<?>[] typeParams = cls.getTypeParameters();
 625  
 
 626  
         // map the arguments to their respective type variables
 627  448
         for (int i = 0; i < typeParams.length; i++) {
 628  234
             final Type typeArg = typeArgs[i];
 629  234
             typeVarAssigns.put(typeParams[i], typeVarAssigns.containsKey(typeArg) ? typeVarAssigns
 630  
                     .get(typeArg) : typeArg);
 631  
         }
 632  
 
 633  214
         if (toClass.equals(cls)) {
 634  
             // target class has been reached. Done.
 635  193
             return typeVarAssigns;
 636  
         }
 637  
 
 638  
         // walk the inheritance hierarchy until the target class is reached
 639  21
         return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
 640  
     }
 641  
 
 642  
     /**
 643  
      * <p> Return a map of the type arguments of a class in the context of <code>toClass</code>. </p>
 644  
      *
 645  
      * @param cls the class in question
 646  
      * @param toClass the context class
 647  
      * @param subtypeVarAssigns a map with type variables
 648  
      * @return the map with type arguments
 649  
      */
 650  
     private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, final Class<?> toClass,
 651  
             final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
 652  
         // make sure they're assignable
 653  43
         if (!isAssignable(cls, toClass)) {
 654  0
             return null;
 655  
         }
 656  
 
 657  
         // can't work with primitives
 658  43
         if (cls.isPrimitive()) {
 659  
             // both classes are primitives?
 660  3
             if (toClass.isPrimitive()) {
 661  
                 // dealing with widening here. No type arguments to be
 662  
                 // harvested with these two types.
 663  0
                 return new HashMap<TypeVariable<?>, Type>();
 664  
             }
 665  
 
 666  
             // work with wrapper the wrapper class instead of the primitive
 667  3
             cls = ClassUtils.primitiveToWrapper(cls);
 668  
         }
 669  
 
 670  
         // create a copy of the incoming map, or an empty one if it's null
 671  43
         final HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
 672  
                 : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
 673  
 
 674  
         // has target class been reached?
 675  43
         if (toClass.equals(cls)) {
 676  19
             return typeVarAssigns;
 677  
         }
 678  
 
 679  
         // walk the inheritance hierarchy until the target class is reached
 680  24
         return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
 681  
     }
 682  
 
 683  
     /**
 684  
      * <p> Tries to determine the type arguments of a class/interface based on a
 685  
      * super parameterized type's type arguments. This method is the inverse of
 686  
      * {@link #getTypeArguments(Type, Class)} which gets a class/interface's
 687  
      * type arguments based on a subtype. It is far more limited in determining
 688  
      * the type arguments for the subject class's type variables in that it can
 689  
      * only determine those parameters that map from the subject {@link Class}
 690  
      * object to the supertype. </p> <p> Example: {@link java.util.TreeSet
 691  
      * TreeSet} sets its parameter as the parameter for
 692  
      * {@link java.util.NavigableSet NavigableSet}, which in turn sets the
 693  
      * parameter of {@link java.util.SortedSet}, which in turn sets the
 694  
      * parameter of {@link Set}, which in turn sets the parameter of
 695  
      * {@link java.util.Collection}, which in turn sets the parameter of
 696  
      * {@link java.lang.Iterable}. Since <code>TreeSet</code>'s parameter maps
 697  
      * (indirectly) to <code>Iterable</code>'s parameter, it will be able to
 698  
      * determine that based on the super type <code>Iterable<? extends
 699  
      * Map<Integer,? extends Collection<?>>></code>, the parameter of
 700  
      * <code>TreeSet</code> is <code>? extends Map<Integer,? extends
 701  
      * Collection<?>></code>. </p>
 702  
      *
 703  
      * @param cls the class whose type parameters are to be determined
 704  
      * @param superType the super type from which <code>cls</code>'s type
 705  
      * arguments are to be determined
 706  
      * @return a map of the type assignments that could be determined for the
 707  
      * type variables in each type in the inheritance hierarchy from
 708  
      * <code>type</code> to <code>toClass</code> inclusive.
 709  
      */
 710  
     public static Map<TypeVariable<?>, Type> determineTypeArguments(final Class<?> cls,
 711  
             final ParameterizedType superType) {
 712  6
         final Class<?> superClass = getRawType(superType);
 713  
 
 714  
         // compatibility check
 715  6
         if (!isAssignable(cls, superClass)) {
 716  0
             return null;
 717  
         }
 718  
 
 719  6
         if (cls.equals(superClass)) {
 720  1
             return getTypeArguments(superType, superClass, null);
 721  
         }
 722  
 
 723  
         // get the next class in the inheritance hierarchy
 724  5
         final Type midType = getClosestParentType(cls, superClass);
 725  
 
 726  
         // can only be a class or a parameterized type
 727  5
         if (midType instanceof Class<?>) {
 728  0
             return determineTypeArguments((Class<?>) midType, superType);
 729  
         }
 730  
 
 731  5
         final ParameterizedType midParameterizedType = (ParameterizedType) midType;
 732  5
         final Class<?> midClass = getRawType(midParameterizedType);
 733  
         // get the type variables of the mid class that map to the type
 734  
         // arguments of the super class
 735  5
         final Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superType);
 736  
         // map the arguments of the mid type to the class type variables
 737  5
         mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
 738  
 
 739  5
         return typeVarAssigns;
 740  
     }
 741  
 
 742  
     /**
 743  
      * <p>Performs a mapping of type variables.</p>
 744  
      *
 745  
      * @param <T> the generic type of the class in question
 746  
      * @param cls the class in question
 747  
      * @param parameterizedType the parameterized type
 748  
      * @param typeVarAssigns the map to be filled
 749  
      */
 750  
     private static <T> void mapTypeVariablesToArguments(final Class<T> cls,
 751  
             final ParameterizedType parameterizedType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
 752  
         // capture the type variables from the owner type that have assignments
 753  5
         final Type ownerType = parameterizedType.getOwnerType();
 754  
 
 755  5
         if (ownerType instanceof ParameterizedType) {
 756  
             // recursion to make sure the owner's owner type gets processed
 757  0
             mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
 758  
         }
 759  
 
 760  
         // parameterizedType is a generic interface/class (or it's in the owner
 761  
         // hierarchy of said interface/class) implemented/extended by the class
 762  
         // cls. Find out which type variables of cls are type arguments of
 763  
         // parameterizedType:
 764  5
         final Type[] typeArgs = parameterizedType.getActualTypeArguments();
 765  
 
 766  
         // of the cls's type variables that are arguments of parameterizedType,
 767  
         // find out which ones can be determined from the super type's arguments
 768  5
         final TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
 769  
 
 770  
         // use List view of type parameters of cls so the contains() method can be used:
 771  5
         final List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls
 772  
                 .getTypeParameters());
 773  
 
 774  10
         for (int i = 0; i < typeArgs.length; i++) {
 775  5
             final TypeVariable<?> typeVar = typeVars[i];
 776  5
             final Type typeArg = typeArgs[i];
 777  
 
 778  
             // argument of parameterizedType is a type variable of cls
 779  5
             if (typeVarList.contains(typeArg)
 780  
             // type variable of parameterizedType has an assignment in
 781  
                     // the super type.
 782  
                     && typeVarAssigns.containsKey(typeVar)) {
 783  
                 // map the assignment to the cls's type variable
 784  5
                 typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
 785  
             }
 786  
         }
 787  5
     }
 788  
 
 789  
     /**
 790  
      * <p> Closest parent type? Closest to what? The closest parent type to the
 791  
      * super class specified by <code>superClass</code>. </p>
 792  
      *
 793  
      * @param cls the class in question
 794  
      * @param superClass the super class
 795  
      * @return the closes parent type
 796  
      */
 797  
     private static Type getClosestParentType(final Class<?> cls, final Class<?> superClass) {
 798  
         // only look at the interfaces if the super class is also an interface
 799  50
         if (superClass.isInterface()) {
 800  
             // get the generic interfaces of the subject class
 801  28
             final Type[] interfaceTypes = cls.getGenericInterfaces();
 802  
             // will hold the best generic interface match found
 803  28
             Type genericInterface = null;
 804  
 
 805  
             // find the interface closest to the super class
 806  57
             for (final Type midType : interfaceTypes) {
 807  29
                 Class<?> midClass = null;
 808  
 
 809  29
                 if (midType instanceof ParameterizedType) {
 810  27
                     midClass = getRawType((ParameterizedType) midType);
 811  2
                 } else if (midType instanceof Class<?>) {
 812  2
                     midClass = (Class<?>) midType;
 813  
                 } else {
 814  0
                     throw new IllegalStateException("Unexpected generic"
 815  
                             + " interface type found: " + midType);
 816  
                 }
 817  
 
 818  
                 // check if this interface is further up the inheritance chain
 819  
                 // than the previously found match
 820  29
                 if (isAssignable(midClass, superClass)
 821  
                         && isAssignable(genericInterface, (Type) midClass)) {
 822  27
                     genericInterface = midType;
 823  
                 }
 824  
             }
 825  
 
 826  
             // found a match?
 827  28
             if (genericInterface != null) {
 828  27
                 return genericInterface;
 829  
             }
 830  
         }
 831  
 
 832  
         // none of the interfaces were descendants of the target class, so the
 833  
         // super class has to be one, instead
 834  23
         return cls.getGenericSuperclass();
 835  
     }
 836  
 
 837  
     /**
 838  
      * <p> Checks if the given value can be assigned to the target type
 839  
      * following the Java generics rules. </p>
 840  
      *
 841  
      * @param value the value to be checked
 842  
      * @param type the target type
 843  
      * @return true of <code>value</code> is an instance of <code>type</code>.
 844  
      */
 845  
     public static boolean isInstance(final Object value, final Type type) {
 846  2
         if (type == null) {
 847  0
             return false;
 848  
         }
 849  
 
 850  2
         return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()
 851  
                 : isAssignable(value.getClass(), type, null);
 852  
     }
 853  
 
 854  
     /**
 855  
      * <p> This method strips out the redundant upper bound types in type
 856  
      * variable types and wildcard types (or it would with wildcard types if
 857  
      * multiple upper bounds were allowed). </p> <p> Example: with the variable
 858  
      * type declaration:
 859  
      *
 860  
      * <pre> &lt;K extends java.util.Collection&lt;String&gt; &amp;
 861  
      * java.util.List&lt;String&gt;&gt; </pre>
 862  
      *
 863  
      * since <code>List</code> is a subinterface of <code>Collection</code>,
 864  
      * this method will return the bounds as if the declaration had been:
 865  
      *
 866  
      * <pre> &lt;K extends java.util.List&lt;String&gt;&gt; </pre>
 867  
      *
 868  
      * </p>
 869  
      *
 870  
      * @param bounds an array of types representing the upper bounds of either
 871  
      * <code>WildcardType</code> or <code>TypeVariable</code>.
 872  
      * @return an array containing the values from <code>bounds</code> minus the
 873  
      * redundant types.
 874  
      */
 875  
     public static Type[] normalizeUpperBounds(final Type[] bounds) {
 876  
         // don't bother if there's only one (or none) type
 877  72
         if (bounds.length < 2) {
 878  71
             return bounds;
 879  
         }
 880  
 
 881  1
         final Set<Type> types = new HashSet<Type>(bounds.length);
 882  
 
 883  3
         for (final Type type1 : bounds) {
 884  2
             boolean subtypeFound = false;
 885  
 
 886  6
             for (final Type type2 : bounds) {
 887  4
                 if (type1 != type2 && isAssignable(type2, type1, null)) {
 888  0
                     subtypeFound = true;
 889  0
                     break;
 890  
                 }
 891  
             }
 892  
 
 893  2
             if (!subtypeFound) {
 894  2
                 types.add(type1);
 895  
             }
 896  
         }
 897  
 
 898  1
         return types.toArray(new Type[types.size()]);
 899  
     }
 900  
 
 901  
     /**
 902  
      * <p> Returns an array containing the sole type of {@link Object} if
 903  
      * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it
 904  
      * returns the result of <code>TypeVariable.getBounds()</code> passed into
 905  
      * {@link #normalizeUpperBounds}. </p>
 906  
      *
 907  
      * @param typeVariable the subject type variable
 908  
      * @return a non-empty array containing the bounds of the type variable.
 909  
      */
 910  
     public static Type[] getImplicitBounds(final TypeVariable<?> typeVariable) {
 911  3
         final Type[] bounds = typeVariable.getBounds();
 912  
 
 913  3
         return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
 914  
     }
 915  
 
 916  
     /**
 917  
      * <p> Returns an array containing the sole value of {@link Object} if
 918  
      * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise,
 919  
      * it returns the result of <code>WildcardType.getUpperBounds()</code>
 920  
      * passed into {@link #normalizeUpperBounds}. </p>
 921  
      *
 922  
      * @param wildcardType the subject wildcard type
 923  
      * @return a non-empty array containing the upper bounds of the wildcard
 924  
      * type.
 925  
      */
 926  
     public static Type[] getImplicitUpperBounds(final WildcardType wildcardType) {
 927  68
         final Type[] bounds = wildcardType.getUpperBounds();
 928  
 
 929  68
         return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
 930  
     }
 931  
 
 932  
     /**
 933  
      * <p> Returns an array containing a single value of <code>null</code> if
 934  
      * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise,
 935  
      * it returns the result of <code>WildcardType.getLowerBounds()</code>. </p>
 936  
      *
 937  
      * @param wildcardType the subject wildcard type
 938  
      * @return a non-empty array containing the lower bounds of the wildcard
 939  
      * type.
 940  
      */
 941  
     public static Type[] getImplicitLowerBounds(final WildcardType wildcardType) {
 942  68
         final Type[] bounds = wildcardType.getLowerBounds();
 943  
 
 944  68
         return bounds.length == 0 ? new Type[] { null } : bounds;
 945  
     }
 946  
 
 947  
     /**
 948  
      * <p> Determines whether or not specified types satisfy the bounds of their
 949  
      * mapped type variables. When a type parameter extends another (such as
 950  
      * <code><T, S extends T></code>), uses another as a type parameter (such as
 951  
      * <code><T, S extends Comparable<T></code>), or otherwise depends on
 952  
      * another type variable to be specified, the dependencies must be included
 953  
      * in <code>typeVarAssigns</code>. </p>
 954  
      *
 955  
      * @param typeVarAssigns specifies the potential types to be assigned to the
 956  
      * type variables.
 957  
      * @return whether or not the types can be assigned to their respective type
 958  
      * variables.
 959  
      */
 960  
     public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVarAssigns) {
 961  
         // all types must be assignable to all the bounds of the their mapped
 962  
         // type variable.
 963  3
         for (final Map.Entry<TypeVariable<?>, Type> entry : typeVarAssigns.entrySet()) {
 964  3
             final TypeVariable<?> typeVar = entry.getKey();
 965  3
             final Type type = entry.getValue();
 966  
 
 967  6
             for (final Type bound : getImplicitBounds(typeVar)) {
 968  3
                 if (!isAssignable(type, substituteTypeVariables(bound, typeVarAssigns),
 969  
                         typeVarAssigns)) {
 970  0
                     return false;
 971  
                 }
 972  
             }
 973  3
         }
 974  
 
 975  3
         return true;
 976  
     }
 977  
 
 978  
     /**
 979  
      * <p> Transforms the passed in type to a {@code Class} object. Type-checking method of convenience. </p>
 980  
      *
 981  
      * @param parameterizedType the type to be converted
 982  
      * @return the corresponding {@code Class} object
 983  
      * @throws IllegalStateException if the conversion fails
 984  
      */
 985  
     private static Class<?> getRawType(final ParameterizedType parameterizedType) {
 986  386
         final Type rawType = parameterizedType.getRawType();
 987  
 
 988  
         // check if raw type is a Class object
 989  
         // not currently necessary, but since the return type is Type instead of
 990  
         // Class, there's enough reason to believe that future versions of Java
 991  
         // may return other Type implementations. And type-safety checking is
 992  
         // rarely a bad idea.
 993  386
         if (!(rawType instanceof Class<?>)) {
 994  0
             throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType);
 995  
         }
 996  
 
 997  386
         return (Class<?>) rawType;
 998  
     }
 999  
 
 1000  
     /**
 1001  
      * <p> Get the raw type of a Java type, given its context. Primarily for use
 1002  
      * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
 1003  
      * not know the runtime type of <code>type</code>: if you know you have a
 1004  
      * {@link Class} instance, it is already raw; if you know you have a
 1005  
      * {@link ParameterizedType}, its raw type is only a method call away. </p>
 1006  
      *
 1007  
      * @param type to resolve
 1008  
      * @param assigningType type to be resolved against
 1009  
      * @return the resolved <code>Class</code> object or <code>null</code> if
 1010  
      * the type could not be resolved
 1011  
      */
 1012  
     public static Class<?> getRawType(final Type type, final Type assigningType) {
 1013  14
         if (type instanceof Class<?>) {
 1014  
             // it is raw, no problem
 1015  4
             return (Class<?>) type;
 1016  
         }
 1017  
 
 1018  10
         if (type instanceof ParameterizedType) {
 1019  
             // simple enough to get the raw type of a ParameterizedType
 1020  4
             return getRawType((ParameterizedType) type);
 1021  
         }
 1022  
 
 1023  6
         if (type instanceof TypeVariable<?>) {
 1024  5
             if (assigningType == null) {
 1025  0
                 return null;
 1026  
             }
 1027  
 
 1028  
             // get the entity declaring this type variable
 1029  5
             final Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
 1030  
 
 1031  
             // can't get the raw type of a method- or constructor-declared type
 1032  
             // variable
 1033  5
             if (!(genericDeclaration instanceof Class<?>)) {
 1034  0
                 return null;
 1035  
             }
 1036  
 
 1037  
             // get the type arguments for the declaring class/interface based
 1038  
             // on the enclosing type
 1039  5
             final Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType,
 1040  
                     (Class<?>) genericDeclaration);
 1041  
 
 1042  
             // enclosingType has to be a subclass (or subinterface) of the
 1043  
             // declaring type
 1044  5
             if (typeVarAssigns == null) {
 1045  0
                 return null;
 1046  
             }
 1047  
 
 1048  
             // get the argument assigned to this type variable
 1049  5
             final Type typeArgument = typeVarAssigns.get(type);
 1050  
 
 1051  5
             if (typeArgument == null) {
 1052  1
                 return null;
 1053  
             }
 1054  
 
 1055  
             // get the argument for this type variable
 1056  4
             return getRawType(typeArgument, assigningType);
 1057  
         }
 1058  
 
 1059  1
         if (type instanceof GenericArrayType) {
 1060  
             // get raw component type
 1061  1
             final Class<?> rawComponentType = getRawType(((GenericArrayType) type)
 1062  
                     .getGenericComponentType(), assigningType);
 1063  
 
 1064  
             // create array type from raw component type and return its class
 1065  1
             return Array.newInstance(rawComponentType, 0).getClass();
 1066  
         }
 1067  
 
 1068  
         // (hand-waving) this is not the method you're looking for
 1069  0
         if (type instanceof WildcardType) {
 1070  0
             return null;
 1071  
         }
 1072  
 
 1073  0
         throw new IllegalArgumentException("unknown type: " + type);
 1074  
     }
 1075  
 
 1076  
     /**
 1077  
      * Learn whether the specified type denotes an array type.
 1078  
      * @param type the type to be checked
 1079  
      * @return <code>true</code> if <code>type</code> is an array class or a {@link GenericArrayType}.
 1080  
      */
 1081  
     public static boolean isArrayType(final Type type) {
 1082  34
         return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
 1083  
     }
 1084  
 
 1085  
     /**
 1086  
      * Get the array component type of <code>type</code>.
 1087  
      * @param type the type to be checked
 1088  
      * @return component type or null if type is not an array type
 1089  
      */
 1090  
     public static Type getArrayComponentType(final Type type) {
 1091  30
         if (type instanceof Class<?>) {
 1092  18
             final Class<?> clazz = (Class<?>) type;
 1093  18
             return clazz.isArray() ? clazz.getComponentType() : null;
 1094  
         }
 1095  12
         if (type instanceof GenericArrayType) {
 1096  6
             return ((GenericArrayType) type).getGenericComponentType();
 1097  
         }
 1098  6
         return null;
 1099  
     }
 1100  
 
 1101  
 }