You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2020/11/15 15:40:37 UTC

[commons-lang] branch master updated (0e2ebd3 -> 43b2326)

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git.


    from 0e2ebd3  [LANG-1541] ArrayUtils.contains() and indexOf() fails to handle Double.NaN #647.
     new 46cdc66  Javadoc.
     new fe1c790  Sort members.
     new 43b2326  Consistently use just the parameter name for the message of NullPointerExceptions.

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../java/org/apache/commons/lang3/CharRange.java   |    2 +-
 .../java/org/apache/commons/lang3/CharUtils.java   |    4 +-
 .../org/apache/commons/lang3/ClassPathUtils.java   |   16 +-
 .../java/org/apache/commons/lang3/ClassUtils.java  |    2 +-
 .../java/org/apache/commons/lang3/ObjectUtils.java |   10 +-
 src/main/java/org/apache/commons/lang3/Range.java  |    2 +-
 .../apache/commons/lang3/SerializationUtils.java   |    2 +-
 .../java/org/apache/commons/lang3/ThreadUtils.java |   14 +-
 .../apache/commons/lang3/builder/DiffBuilder.java  |    8 +-
 .../apache/commons/lang3/builder/DiffResult.java   |   24 +-
 .../commons/lang3/builder/HashCodeBuilder.java     |    2 +-
 .../lang3/builder/ReflectionToStringBuilder.java   |    2 +-
 .../commons/lang3/builder/ToStringBuilder.java     |    2 +-
 .../lang3/concurrent/BasicThreadFactory.java       |    6 +-
 .../concurrent/CallableBackgroundInitializer.java  |    6 +-
 .../concurrent/MultiBackgroundInitializer.java     |   13 +-
 .../commons/lang3/event/EventListenerSupport.java  |    8 +-
 .../org/apache/commons/lang3/math/Fraction.java    |    8 +-
 .../apache/commons/lang3/math/IEEE754rUtils.java   |    8 +-
 .../org/apache/commons/lang3/math/NumberUtils.java |    2 +-
 .../commons/lang3/reflect/ConstructorUtils.java    |    6 +-
 .../apache/commons/lang3/reflect/FieldUtils.java   |   26 +-
 .../apache/commons/lang3/reflect/MethodUtils.java  |   12 +-
 .../apache/commons/lang3/reflect/TypeUtils.java    | 2445 ++++++++++----------
 .../org/apache/commons/lang3/time/DateUtils.java   |    2 +-
 .../org/apache/commons/lang3/time/FormatCache.java |    2 +-
 .../org/apache/commons/lang3/CharRangeTest.java    |    2 +-
 27 files changed, 1332 insertions(+), 1304 deletions(-)


[commons-lang] 02/03: Sort members.

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git

commit fe1c7903a8b97badb59f4c63b440c35bee4cf6c1
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Nov 15 09:37:29 2020 -0500

    Sort members.
---
 .../apache/commons/lang3/reflect/TypeUtils.java    | 2390 ++++++++++----------
 1 file changed, 1195 insertions(+), 1195 deletions(-)

diff --git a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
index 35ad795..5fe03af 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
@@ -47,49 +47,6 @@ import org.apache.commons.lang3.builder.Builder;
 public class TypeUtils {
 
     /**
-     * {@link WildcardType} builder.
-     * @since 3.2
-     */
-    public static class WildcardTypeBuilder implements Builder<WildcardType> {
-        /**
-         * Constructor
-         */
-        private WildcardTypeBuilder() {
-        }
-
-        private Type[] upperBounds;
-        private Type[] lowerBounds;
-
-        /**
-         * Specify upper bounds of the wildcard type to build.
-         * @param bounds to set
-         * @return {@code this}
-         */
-        public WildcardTypeBuilder withUpperBounds(final Type... bounds) {
-            this.upperBounds = bounds;
-            return this;
-        }
-
-        /**
-         * Specify lower bounds of the wildcard type to build.
-         * @param bounds to set
-         * @return {@code this}
-         */
-        public WildcardTypeBuilder withLowerBounds(final Type... bounds) {
-            this.lowerBounds = bounds;
-            return this;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public WildcardType build() {
-            return new WildcardTypeImpl(upperBounds, lowerBounds);
-        }
-    }
-
-    /**
      * GenericArrayType implementation class.
      * @since 3.2
      */
@@ -108,34 +65,34 @@ public class TypeUtils {
          * {@inheritDoc}
          */
         @Override
-        public Type getGenericComponentType() {
-            return componentType;
+        public boolean equals(final Object obj) {
+            return obj == this || obj instanceof GenericArrayType && TypeUtils.equals(this, (GenericArrayType) obj);
         }
 
         /**
          * {@inheritDoc}
          */
         @Override
-        public String toString() {
-            return TypeUtils.toString(this);
+        public Type getGenericComponentType() {
+            return componentType;
         }
 
         /**
          * {@inheritDoc}
          */
         @Override
-        public boolean equals(final Object obj) {
-            return obj == this || obj instanceof GenericArrayType && TypeUtils.equals(this, (GenericArrayType) obj);
+        public int hashCode() {
+            int result = 67 << 4;
+            result |= componentType.hashCode();
+            return result;
         }
 
         /**
          * {@inheritDoc}
          */
         @Override
-        public int hashCode() {
-            int result = 67 << 4;
-            result |= componentType.hashCode();
-            return result;
+        public String toString() {
+            return TypeUtils.toString(this);
         }
     }
 
@@ -164,16 +121,8 @@ public class TypeUtils {
          * {@inheritDoc}
          */
         @Override
-        public Type getRawType() {
-            return raw;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Type getOwnerType() {
-            return useOwner;
+        public boolean equals(final Object obj) {
+            return obj == this || obj instanceof ParameterizedType && TypeUtils.equals(this, ((ParameterizedType) obj));
         }
 
         /**
@@ -188,16 +137,16 @@ public class TypeUtils {
          * {@inheritDoc}
          */
         @Override
-        public String toString() {
-            return TypeUtils.toString(this);
+        public Type getOwnerType() {
+            return useOwner;
         }
 
         /**
          * {@inheritDoc}
          */
         @Override
-        public boolean equals(final Object obj) {
-            return obj == this || obj instanceof ParameterizedType && TypeUtils.equals(this, ((ParameterizedType) obj));
+        public Type getRawType() {
+            return raw;
         }
 
         /**
@@ -213,6 +162,57 @@ public class TypeUtils {
             result |= Arrays.hashCode(typeArguments);
             return result;
         }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public String toString() {
+            return TypeUtils.toString(this);
+        }
+    }
+
+    /**
+     * {@link WildcardType} builder.
+     * @since 3.2
+     */
+    public static class WildcardTypeBuilder implements Builder<WildcardType> {
+        private Type[] upperBounds;
+
+        private Type[] lowerBounds;
+        /**
+         * Constructor
+         */
+        private WildcardTypeBuilder() {
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public WildcardType build() {
+            return new WildcardTypeImpl(upperBounds, lowerBounds);
+        }
+
+        /**
+         * Specify lower bounds of the wildcard type to build.
+         * @param bounds to set
+         * @return {@code this}
+         */
+        public WildcardTypeBuilder withLowerBounds(final Type... bounds) {
+            this.lowerBounds = bounds;
+            return this;
+        }
+
+        /**
+         * Specify upper bounds of the wildcard type to build.
+         * @param bounds to set
+         * @return {@code this}
+         */
+        public WildcardTypeBuilder withUpperBounds(final Type... bounds) {
+            this.upperBounds = bounds;
+            return this;
+        }
     }
 
     /**
@@ -237,8 +237,8 @@ public class TypeUtils {
          * {@inheritDoc}
          */
         @Override
-        public Type[] getUpperBounds() {
-            return upperBounds.clone();
+        public boolean equals(final Object obj) {
+            return obj == this || obj instanceof WildcardType && TypeUtils.equals(this, (WildcardType) obj);
         }
 
         /**
@@ -253,16 +253,8 @@ public class TypeUtils {
          * {@inheritDoc}
          */
         @Override
-        public String toString() {
-            return TypeUtils.toString(this);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public boolean equals(final Object obj) {
-            return obj == this || obj instanceof WildcardType && TypeUtils.equals(this, (WildcardType) obj);
+        public Type[] getUpperBounds() {
+            return upperBounds.clone();
         }
 
         /**
@@ -276,6 +268,14 @@ public class TypeUtils {
             result |= Arrays.hashCode(lowerBounds);
             return result;
         }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public String toString() {
+            return TypeUtils.toString(this);
+        }
     }
 
     /**
@@ -285,455 +285,566 @@ public class TypeUtils {
     public static final WildcardType WILDCARD_ALL = wildcardType().withUpperBounds(Object.class).build();
 
     /**
-     * {@code TypeUtils} instances should NOT be constructed in standard
-     * programming. Instead, the class should be used as
-     * {@code TypeUtils.isAssignable(cls, toClass)}.
-     * <p>
-     * This constructor is public to permit tools that require a JavaBean instance
-     * to operate.
-     * </p>
+     * Appends {@code types} to {@code builder} with separator {@code sep}.
+     *
+     * @param builder destination
+     * @param sep separator
+     * @param types to append
+     * @return {@code builder}
+     * @since 3.2
      */
-    public TypeUtils() {
-        super();
+    private static <T> StringBuilder appendAllTo(final StringBuilder builder, final String sep,
+        @SuppressWarnings("unchecked") final T... types) {
+        Validate.notEmpty(Validate.noNullElements(types));
+        if (types.length > 0) {
+            builder.append(toString(types[0]));
+            for (int i = 1; i < types.length; i++) {
+                builder.append(sep).append(toString(types[i]));
+            }
+        }
+        return builder;
     }
 
-    /**
-     * Tests if the subject type may be implicitly cast to the target type
-     * following the Java generics rules. If both types are {@link Class}
-     * objects, the method returns the result of
-     * {@link ClassUtils#isAssignable(Class, Class)}.
-     *
-     * @param type the subject type to be assigned to the target type
-     * @param toType the target type
-     * @return {@code true} if {@code type} is assignable to {@code toType}.
-     */
-    public static boolean isAssignable(final Type type, final Type toType) {
-        return isAssignable(type, toType, null);
+    private static void appendRecursiveTypes(final StringBuilder builder, final int[] recursiveTypeIndexes,
+        final Type[] argumentTypes) {
+        for (int i = 0; i < recursiveTypeIndexes.length; i++) {
+            appendAllTo(builder.append('<'), ", ", argumentTypes[i].toString()).append('>');
+        }
+
+        final Type[] argumentsFiltered = ArrayUtils.removeAll(argumentTypes, recursiveTypeIndexes);
+
+        if (argumentsFiltered.length > 0) {
+            appendAllTo(builder.append('<'), ", ", argumentsFiltered).append('>');
+        }
     }
 
     /**
-     * Tests if the subject type may be implicitly cast to the target type
-     * following the Java generics rules.
+     * Formats a {@link Class} as a {@link String}.
      *
-     * @param type the subject type to be assigned to the target type
-     * @param toType the target type
-     * @param typeVarAssigns optional map of type variable assignments
-     * @return {@code true} if {@code type} is assignable to {@code toType}.
+     * @param cls {@code Class} to format
+     * @return String
+     * @since 3.2
      */
-    private static boolean isAssignable(final Type type, final Type toType,
-            final Map<TypeVariable<?>, Type> typeVarAssigns) {
-        if (toType == null || toType instanceof Class<?>) {
-            return isAssignable(type, (Class<?>) toType);
-        }
-
-        if (toType instanceof ParameterizedType) {
-            return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
+    private static String classToString(final Class<?> cls) {
+        if (cls.isArray()) {
+            return toString(cls.getComponentType()) + "[]";
         }
 
-        if (toType instanceof GenericArrayType) {
-            return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
-        }
+        final StringBuilder buf = new StringBuilder();
 
-        if (toType instanceof WildcardType) {
-            return isAssignable(type, (WildcardType) toType, typeVarAssigns);
+        if (cls.getEnclosingClass() != null) {
+            buf.append(classToString(cls.getEnclosingClass())).append('.').append(cls.getSimpleName());
+        } else {
+            buf.append(cls.getName());
         }
-
-        if (toType instanceof TypeVariable<?>) {
-            return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
+        if (cls.getTypeParameters().length > 0) {
+            buf.append('<');
+            appendAllTo(buf, ", ", cls.getTypeParameters());
+            buf.append('>');
         }
-
-        throw new IllegalStateException("found an unhandled type: " + toType);
+        return buf.toString();
     }
 
     /**
-     * Tests if the subject type may be implicitly cast to the target class
-     * following the Java generics rules.
+     * Tests, recursively, whether any of the type parameters associated with {@code type} are bound to variables.
      *
-     * @param type the subject type to be assigned to the target type
-     * @param toClass the target class
-     * @return {@code true} if {@code type} is assignable to {@code toClass}.
-     */
-    private static boolean isAssignable(final Type type, final Class<?> toClass) {
-        if (type == null) {
-            // consistency with ClassUtils.isAssignable() behavior
-            return toClass == null || !toClass.isPrimitive();
-        }
-
-        // only a null type can be assigned to null type which
-        // would have cause the previous to return true
-        if (toClass == null) {
-            return false;
-        }
-
-        // all types are assignable to themselves
-        if (toClass.equals(type)) {
+     * @param type the type to check for type variables
+     * @return boolean
+     * @since 3.2
+     */
+    public static boolean containsTypeVariables(final Type type) {
+        if (type instanceof TypeVariable<?>) {
             return true;
         }
-
         if (type instanceof Class<?>) {
-            // just comparing two classes
-            return ClassUtils.isAssignable((Class<?>) type, toClass);
+            return ((Class<?>) type).getTypeParameters().length > 0;
         }
-
         if (type instanceof ParameterizedType) {
-            // only have to compare the raw type to the class
-            return isAssignable(getRawType((ParameterizedType) type), toClass);
-        }
-
-        // *
-        if (type instanceof TypeVariable<?>) {
-            // if any of the bounds are assignable to the class, then the
-            // type is assignable to the class.
-            for (final Type bound : ((TypeVariable<?>) type).getBounds()) {
-                if (isAssignable(bound, toClass)) {
+            for (final Type arg : ((ParameterizedType) type).getActualTypeArguments()) {
+                if (containsTypeVariables(arg)) {
                     return true;
                 }
             }
-
             return false;
         }
-
-        // the only classes to which a generic array type can be assigned
-        // are class Object and array classes
-        if (type instanceof GenericArrayType) {
-            return toClass.equals(Object.class)
-                    || toClass.isArray()
-                    && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass
-                            .getComponentType());
-        }
-
-        // wildcard types are not assignable to a class (though one would think
-        // "? super Object" would be assignable to Object)
         if (type instanceof WildcardType) {
-            return false;
+            final WildcardType wild = (WildcardType) type;
+            return containsTypeVariables(getImplicitLowerBounds(wild)[0])
+                || containsTypeVariables(getImplicitUpperBounds(wild)[0]);
         }
+        return false;
+    }
 
-        throw new IllegalStateException("found an unhandled type: " + type);
+    private static boolean containsVariableTypeSameParametrizedTypeBound(final TypeVariable<?> typeVariable,
+        final ParameterizedType parameterizedType) {
+        return ArrayUtils.contains(typeVariable.getBounds(), parameterizedType);
     }
 
     /**
-     * Tests if the subject type may be implicitly cast to the target
-     * parameterized type following the Java generics rules.
+     * Tries to determine the type arguments of a class/interface based on a
+     * super parameterized type's type arguments. This method is the inverse of
+     * {@link #getTypeArguments(Type, Class)} which gets a class/interface's
+     * type arguments based on a subtype. It is far more limited in determining
+     * the type arguments for the subject class's type variables in that it can
+     * only determine those parameters that map from the subject {@link Class}
+     * object to the supertype.
+     * 
+     * <p>
+     * Example: {@link java.util.TreeSet
+     * TreeSet} sets its parameter as the parameter for
+     * {@link java.util.NavigableSet NavigableSet}, which in turn sets the
+     * parameter of {@link java.util.SortedSet}, which in turn sets the
+     * parameter of {@link Set}, which in turn sets the parameter of
+     * {@link java.util.Collection}, which in turn sets the parameter of
+     * {@link java.lang.Iterable}. Since {@code TreeSet}'s parameter maps
+     * (indirectly) to {@code Iterable}'s parameter, it will be able to
+     * determine that based on the super type {@code Iterable<? extends
+     * Map<Integer, ? extends Collection<?>>>}, the parameter of
+     * {@code TreeSet} is {@code ? extends Map<Integer, ? extends
+     * Collection<?>>}.
+     * </p>
      *
-     * @param type the subject type to be assigned to the target type
-     * @param toParameterizedType the target parameterized type
-     * @param typeVarAssigns a map with type variables
-     * @return {@code true} if {@code type} is assignable to {@code toType}.
+     * @param cls the class whose type parameters are to be determined, not {@code null}
+     * @param superType the super type from which {@code cls}'s type
+     * arguments are to be determined, not {@code null}
+     * @return a {@code Map} of the type assignments that could be determined
+     * for the type variables in each type in the inheritance hierarchy from
+     * {@code type} to {@code toClass} inclusive.
      */
-    private static boolean isAssignable(final Type type, final ParameterizedType toParameterizedType,
-            final Map<TypeVariable<?>, Type> typeVarAssigns) {
-        if (type == null) {
-            return true;
-        }
+    public static Map<TypeVariable<?>, Type> determineTypeArguments(final Class<?> cls,
+            final ParameterizedType superType) {
+        Validate.notNull(cls, "cls is null");
+        Validate.notNull(superType, "superType is null");
 
-        // only a null type can be assigned to null type which
-        // would have cause the previous to return true
-        if (toParameterizedType == null) {
-            return false;
-        }
+        final Class<?> superClass = getRawType(superType);
 
-        // all types are assignable to themselves
-        if (toParameterizedType.equals(type)) {
-            return true;
+        // compatibility check
+        if (!isAssignable(cls, superClass)) {
+            return null;
         }
 
-        // get the target type's raw type
-        final Class<?> toClass = getRawType(toParameterizedType);
-        // get the subject type's type arguments including owner type arguments
-        // and supertype arguments up to and including the target class.
-        final Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
-
-        // null means the two types are not compatible
-        if (fromTypeVarAssigns == null) {
-            return false;
+        if (cls.equals(superClass)) {
+            return getTypeArguments(superType, superClass, null);
         }
 
-        // compatible types, but there's no type arguments. this is equivalent
-        // to comparing Map< ?, ? > to Map, and raw types are always assignable
-        // to parameterized types.
-        if (fromTypeVarAssigns.isEmpty()) {
-            return true;
-        }
+        // get the next class in the inheritance hierarchy
+        final Type midType = getClosestParentType(cls, superClass);
 
-        // get the target type's type arguments including owner type arguments
-        final Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType,
-                toClass, typeVarAssigns);
+        // can only be a class or a parameterized type
+        if (midType instanceof Class<?>) {
+            return determineTypeArguments((Class<?>) midType, superType);
+        }
 
-        // now to check each type argument
-        for (final TypeVariable<?> var : toTypeVarAssigns.keySet()) {
-            final Type toTypeArg = unrollVariableAssignments(var, toTypeVarAssigns);
-            final Type fromTypeArg = unrollVariableAssignments(var, fromTypeVarAssigns);
+        final ParameterizedType midParameterizedType = (ParameterizedType) midType;
+        final Class<?> midClass = getRawType(midParameterizedType);
+        // get the type variables of the mid class that map to the type
+        // arguments of the super class
+        final Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superType);
+        // map the arguments of the mid type to the class type variables
+        mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
 
-            if (toTypeArg == null && fromTypeArg instanceof Class) {
-                continue;
-            }
+        return typeVarAssigns;
+    }
 
-            // parameters must either be absent from the subject type, within
-            // the bounds of the wildcard type, or be an exact match to the
-            // parameters of the target type.
-            if (fromTypeArg != null
-                    && !toTypeArg.equals(fromTypeArg)
-                    && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg,
-                            typeVarAssigns))) {
-                return false;
-            }
-        }
-        return true;
+    /**
+     * Tests whether {@code t} equals {@code a}.
+     *
+     * @param genericArrayType LHS
+     * @param type RHS
+     * @return boolean
+     * @since 3.2
+     */
+    private static boolean equals(final GenericArrayType genericArrayType, final Type type) {
+        return type instanceof GenericArrayType
+            && equals(genericArrayType.getGenericComponentType(), ((GenericArrayType) type).getGenericComponentType());
     }
 
     /**
-     * Look up {@code var} in {@code typeVarAssigns} <em>transitively</em>,
-     * i.e. keep looking until the value found is <em>not</em> a type variable.
+     * Tests whether {@code t} equals {@code p}.
      *
-     * @param typeVariable the type variable to look up
-     * @param typeVarAssigns the map used for the look up
-     * @return Type or {@code null} if some variable was not in the map
+     * @param parameterizedType LHS
+     * @param type RHS
+     * @return boolean
      * @since 3.2
      */
-    private static Type unrollVariableAssignments(TypeVariable<?> typeVariable,
-        final Map<TypeVariable<?>, Type> typeVarAssigns) {
-        Type result;
-        do {
-            result = typeVarAssigns.get(typeVariable);
-            if (result instanceof TypeVariable<?> && !result.equals(typeVariable)) {
-                typeVariable = (TypeVariable<?>) result;
-                continue;
+    private static boolean equals(final ParameterizedType parameterizedType, final Type type) {
+        if (type instanceof ParameterizedType) {
+            final ParameterizedType other = (ParameterizedType) type;
+            if (equals(parameterizedType.getRawType(), other.getRawType())
+                && equals(parameterizedType.getOwnerType(), other.getOwnerType())) {
+                return equals(parameterizedType.getActualTypeArguments(), other.getActualTypeArguments());
             }
-            break;
-        } while (true);
-        return result;
+        }
+        return false;
     }
 
     /**
-     * Tests if the subject type may be implicitly cast to the target
-     * generic array type following the Java generics rules.
+     * Tests equality of types.
      *
-     * @param type the subject type to be assigned to the target type
-     * @param toGenericArrayType the target generic array type
-     * @param typeVarAssigns a map with type variables
-     * @return {@code true} if {@code type} is assignable to
-     * {@code toGenericArrayType}.
+     * @param type1 the first type
+     * @param type2 the second type
+     * @return boolean
+     * @since 3.2
      */
-    private static boolean isAssignable(final Type type, final GenericArrayType toGenericArrayType,
-            final Map<TypeVariable<?>, Type> typeVarAssigns) {
-        if (type == null) {
+    public static boolean equals(final Type type1, final Type type2) {
+        if (Objects.equals(type1, type2)) {
             return true;
         }
-
-        // only a null type can be assigned to null type which
-        // would have cause the previous to return true
-        if (toGenericArrayType == null) {
-            return false;
-        }
-
-        // all types are assignable to themselves
-        if (toGenericArrayType.equals(type)) {
-            return true;
+        if (type1 instanceof ParameterizedType) {
+            return equals((ParameterizedType) type1, type2);
         }
-
-        final Type toComponentType = toGenericArrayType.getGenericComponentType();
-
-        if (type instanceof Class<?>) {
-            final Class<?> cls = (Class<?>) type;
-
-            // compare the component types
-            return cls.isArray()
-                    && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
+        if (type1 instanceof GenericArrayType) {
+            return equals((GenericArrayType) type1, type2);
         }
-
-        if (type instanceof GenericArrayType) {
-            // compare the component types
-            return isAssignable(((GenericArrayType) type).getGenericComponentType(),
-                    toComponentType, typeVarAssigns);
+        if (type1 instanceof WildcardType) {
+            return equals((WildcardType) type1, type2);
         }
+        return false;
+    }
 
-        if (type instanceof WildcardType) {
-            // so long as one of the upper bounds is assignable, it's good
-            for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
-                if (isAssignable(bound, toGenericArrayType)) {
-                    return true;
+    /**
+     * Tests whether {@code t1} equals {@code t2}.
+     *
+     * @param type1 LHS
+     * @param type2 RHS
+     * @return boolean
+     * @since 3.2
+     */
+    private static boolean equals(final Type[] type1, final Type[] type2) {
+        if (type1.length == type2.length) {
+            for (int i = 0; i < type1.length; i++) {
+                if (!equals(type1[i], type2[i])) {
+                    return false;
                 }
             }
-
-            return false;
+            return true;
         }
+        return false;
+    }
 
-        if (type instanceof TypeVariable<?>) {
-            // probably should remove the following logic and just return false.
-            // type variables cannot specify arrays as bounds.
-            for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
-                if (isAssignable(bound, toGenericArrayType)) {
-                    return true;
-                }
-            }
+    /**
+     * Tests whether {@code t} equals {@code w}.
+     *
+     * @param wildcardType LHS
+     * @param type RHS
+     * @return boolean
+     * @since 3.2
+     */
+    private static boolean equals(final WildcardType wildcardType, final Type type) {
+        if (type instanceof WildcardType) {
+            final WildcardType other = (WildcardType) type;
+            return equals(getImplicitLowerBounds(wildcardType), getImplicitLowerBounds(other))
+                && equals(getImplicitUpperBounds(wildcardType), getImplicitUpperBounds(other));
+        }
+        return false;
+    }
 
-            return false;
+    /**
+     * Helper method to establish the formal parameters for a parameterized type.
+     *
+     * @param mappings map containing the assignments
+     * @param variables expected map keys
+     * @return array of map values corresponding to specified keys
+     */
+    private static Type[] extractTypeArgumentsFrom(final Map<TypeVariable<?>, Type> mappings, final TypeVariable<?>[] variables) {
+        final Type[] result = new Type[variables.length];
+        int index = 0;
+        for (final TypeVariable<?> var : variables) {
+            Validate.isTrue(mappings.containsKey(var), "missing argument mapping for %s", toString(var));
+            result[index++] = mappings.get(var);
         }
+        return result;
+    }
 
-        if (type instanceof ParameterizedType) {
-            // the raw type of a parameterized type is never an array or
-            // generic array, otherwise the declaration would look like this:
-            // Collection[]< ? extends String > collection;
-            return false;
+    private static int[] findRecursiveTypes(final ParameterizedType parameterizedType) {
+        final Type[] filteredArgumentTypes = Arrays.copyOf(parameterizedType.getActualTypeArguments(),
+            parameterizedType.getActualTypeArguments().length);
+        int[] indexesToRemove = {};
+        for (int i = 0; i < filteredArgumentTypes.length; i++) {
+            if (filteredArgumentTypes[i] instanceof TypeVariable<?>) {
+                if (containsVariableTypeSameParametrizedTypeBound(((TypeVariable<?>) filteredArgumentTypes[i]),
+                    parameterizedType)) {
+                    indexesToRemove = ArrayUtils.add(indexesToRemove, i);
+                }
+            }
         }
+        return indexesToRemove;
+    }
 
-        throw new IllegalStateException("found an unhandled type: " + type);
+    /**
+     * Creates a generic array type instance.
+     *
+     * @param componentType the type of the elements of the array. For example the component type of {@code boolean[]}
+     *                      is {@code boolean}
+     * @return {@link GenericArrayType}
+     * @since 3.2
+     */
+    public static GenericArrayType genericArrayType(final Type componentType) {
+        return new GenericArrayTypeImpl(Validate.notNull(componentType, "componentType is null"));
     }
 
     /**
-     * Tests if the subject type may be implicitly cast to the target
-     * wildcard type following the Java generics rules.
+     * Formats a {@link GenericArrayType} as a {@link String}.
      *
-     * @param type the subject type to be assigned to the target type
-     * @param toWildcardType the target wildcard type
-     * @param typeVarAssigns a map with type variables
-     * @return {@code true} if {@code type} is assignable to
-     * {@code toWildcardType}.
+     * @param genericArrayType {@code GenericArrayType} to format
+     * @return String
+     * @since 3.2
      */
-    private static boolean isAssignable(final Type type, final WildcardType toWildcardType,
-            final Map<TypeVariable<?>, Type> typeVarAssigns) {
-        if (type == null) {
-            return true;
-        }
+    private static String genericArrayTypeToString(final GenericArrayType genericArrayType) {
+        return String.format("%s[]", toString(genericArrayType.getGenericComponentType()));
+    }
 
-        // only a null type can be assigned to null type which
-        // would have cause the previous to return true
-        if (toWildcardType == null) {
-            return false;
+    /**
+     * Gets the array component type of {@code type}.
+     *
+     * @param type the type to be checked
+     * @return component type or null if type is not an array type
+     */
+    public static Type getArrayComponentType(final Type type) {
+        if (type instanceof Class<?>) {
+            final Class<?> cls = (Class<?>) type;
+            return cls.isArray() ? cls.getComponentType() : null;
         }
-
-        // all types are assignable to themselves
-        if (toWildcardType.equals(type)) {
-            return true;
+        if (type instanceof GenericArrayType) {
+            return ((GenericArrayType) type).getGenericComponentType();
         }
+        return null;
+    }
 
-        final Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
-        final Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
-
-        if (type instanceof WildcardType) {
-            final WildcardType wildcardType = (WildcardType) type;
-            final Type[] upperBounds = getImplicitUpperBounds(wildcardType);
-            final Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
+    /**
+     * Gets the closest parent type to the
+     * super class specified by {@code superClass}.
+     *
+     * @param cls the class in question
+     * @param superClass the super class
+     * @return the closes parent type
+     */
+    private static Type getClosestParentType(final Class<?> cls, final Class<?> superClass) {
+        // only look at the interfaces if the super class is also an interface
+        if (superClass.isInterface()) {
+            // get the generic interfaces of the subject class
+            final Type[] interfaceTypes = cls.getGenericInterfaces();
+            // will hold the best generic interface match found
+            Type genericInterface = null;
 
-            for (Type toBound : toUpperBounds) {
-                // if there are assignments for unresolved type variables,
-                // now's the time to substitute them.
-                toBound = substituteTypeVariables(toBound, typeVarAssigns);
+            // find the interface closest to the super class
+            for (final Type midType : interfaceTypes) {
+                Class<?> midClass = null;
 
-                // each upper bound of the subject type has to be assignable to
-                // each
-                // upper bound of the target type
-                for (final Type bound : upperBounds) {
-                    if (!isAssignable(bound, toBound, typeVarAssigns)) {
-                        return false;
-                    }
+                if (midType instanceof ParameterizedType) {
+                    midClass = getRawType((ParameterizedType) midType);
+                } else if (midType instanceof Class<?>) {
+                    midClass = (Class<?>) midType;
+                } else {
+                    throw new IllegalStateException("Unexpected generic"
+                            + " interface type found: " + midType);
                 }
-            }
 
-            for (Type toBound : toLowerBounds) {
-                // if there are assignments for unresolved type variables,
-                // now's the time to substitute them.
-                toBound = substituteTypeVariables(toBound, typeVarAssigns);
-
-                // each lower bound of the target type has to be assignable to
-                // each
-                // lower bound of the subject type
-                for (final Type bound : lowerBounds) {
-                    if (!isAssignable(toBound, bound, typeVarAssigns)) {
-                        return false;
-                    }
+                // check if this interface is further up the inheritance chain
+                // than the previously found match
+                if (isAssignable(midClass, superClass)
+                        && isAssignable(genericInterface, (Type) midClass)) {
+                    genericInterface = midType;
                 }
             }
-            return true;
-        }
 
-        for (final Type toBound : toUpperBounds) {
-            // if there are assignments for unresolved type variables,
-            // now's the time to substitute them.
-            if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns),
-                    typeVarAssigns)) {
-                return false;
+            // found a match?
+            if (genericInterface != null) {
+                return genericInterface;
             }
         }
 
-        for (final Type toBound : toLowerBounds) {
-            // if there are assignments for unresolved type variables,
-            // now's the time to substitute them.
-            if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type,
-                    typeVarAssigns)) {
-                return false;
-            }
+        // none of the interfaces were descendants of the target class, so the
+        // super class has to be one, instead
+        return cls.getGenericSuperclass();
+    }
+
+    /**
+     * Gets an array containing the sole type of {@link Object} if
+     * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it
+     * returns the result of {@link TypeVariable#getBounds()} passed into
+     * {@link #normalizeUpperBounds}.
+     *
+     * @param typeVariable the subject type variable, not {@code null}
+     * @return a non-empty array containing the bounds of the type variable.
+     */
+    public static Type[] getImplicitBounds(final TypeVariable<?> typeVariable) {
+        Validate.notNull(typeVariable, "typeVariable is null");
+        final Type[] bounds = typeVariable.getBounds();
+
+        return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
+    }
+
+    /**
+     * Gets an array containing a single value of {@code null} if
+     * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise,
+     * it returns the result of {@link WildcardType#getLowerBounds()}.
+     *
+     * @param wildcardType the subject wildcard type, not {@code null}
+     * @return a non-empty array containing the lower bounds of the wildcard
+     * type.
+     */
+    public static Type[] getImplicitLowerBounds(final WildcardType wildcardType) {
+        Validate.notNull(wildcardType, "wildcardType is null");
+        final Type[] bounds = wildcardType.getLowerBounds();
+
+        return bounds.length == 0 ? new Type[] { null } : bounds;
+    }
+
+    /**
+     * Gets an array containing the sole value of {@link Object} if
+     * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise,
+     * it returns the result of {@link WildcardType#getUpperBounds()}
+     * passed into {@link #normalizeUpperBounds}.
+     *
+     * @param wildcardType the subject wildcard type, not {@code null}
+     * @return a non-empty array containing the upper bounds of the wildcard
+     * type.
+     */
+    public static Type[] getImplicitUpperBounds(final WildcardType wildcardType) {
+        Validate.notNull(wildcardType, "wildcardType is null");
+        final Type[] bounds = wildcardType.getUpperBounds();
+
+        return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
+    }
+
+    /**
+     * Transforms the passed in type to a {@link Class} object. Type-checking method of convenience.
+     *
+     * @param parameterizedType the type to be converted
+     * @return the corresponding {@code Class} object
+     * @throws IllegalStateException if the conversion fails
+     */
+    private static Class<?> getRawType(final ParameterizedType parameterizedType) {
+        final Type rawType = parameterizedType.getRawType();
+
+        // check if raw type is a Class object
+        // not currently necessary, but since the return type is Type instead of
+        // Class, there's enough reason to believe that future versions of Java
+        // may return other Type implementations. And type-safety checking is
+        // rarely a bad idea.
+        if (!(rawType instanceof Class<?>)) {
+            throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType);
         }
-        return true;
+
+        return (Class<?>) rawType;
     }
 
     /**
-     * Tests if the subject type may be implicitly cast to the target type
-     * variable following the Java generics rules.
+     * Gets the raw type of a Java type, given its context. Primarily for use
+     * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
+     * not know the runtime type of {@code type}: if you know you have a
+     * {@link Class} instance, it is already raw; if you know you have a
+     * {@link ParameterizedType}, its raw type is only a method call away.
      *
-     * @param type the subject type to be assigned to the target type
-     * @param toTypeVariable the target type variable
-     * @param typeVarAssigns a map with type variables
-     * @return {@code true} if {@code type} is assignable to
-     * {@code toTypeVariable}.
+     * @param type to resolve
+     * @param assigningType type to be resolved against
+     * @return the resolved {@link Class} object or {@code null} if
+     * the type could not be resolved
      */
-    private static boolean isAssignable(final Type type, final TypeVariable<?> toTypeVariable,
-            final Map<TypeVariable<?>, Type> typeVarAssigns) {
-        if (type == null) {
-            return true;
+    public static Class<?> getRawType(final Type type, final Type assigningType) {
+        if (type instanceof Class<?>) {
+            // it is raw, no problem
+            return (Class<?>) type;
         }
 
-        // only a null type can be assigned to null type which
-        // would have cause the previous to return true
-        if (toTypeVariable == null) {
-            return false;
+        if (type instanceof ParameterizedType) {
+            // simple enough to get the raw type of a ParameterizedType
+            return getRawType((ParameterizedType) type);
         }
 
-        // all types are assignable to themselves
-        if (toTypeVariable.equals(type)) {
-            return true;
+        if (type instanceof TypeVariable<?>) {
+            if (assigningType == null) {
+                return null;
+            }
+
+            // get the entity declaring this type variable
+            final Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
+
+            // can't get the raw type of a method- or constructor-declared type
+            // variable
+            if (!(genericDeclaration instanceof Class<?>)) {
+                return null;
+            }
+
+            // get the type arguments for the declaring class/interface based
+            // on the enclosing type
+            final Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType,
+                    (Class<?>) genericDeclaration);
+
+            // enclosingType has to be a subclass (or subinterface) of the
+            // declaring type
+            if (typeVarAssigns == null) {
+                return null;
+            }
+
+            // get the argument assigned to this type variable
+            final Type typeArgument = typeVarAssigns.get(type);
+
+            if (typeArgument == null) {
+                return null;
+            }
+
+            // get the argument for this type variable
+            return getRawType(typeArgument, assigningType);
         }
 
-        if (type instanceof TypeVariable<?>) {
-            // a type variable is assignable to another type variable, if
-            // and only if the former is the latter, extends the latter, or
-            // is otherwise a descendant of the latter.
-            final Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
+        if (type instanceof GenericArrayType) {
+            // get raw component type
+            final Class<?> rawComponentType = getRawType(((GenericArrayType) type)
+                    .getGenericComponentType(), assigningType);
 
-            for (final Type bound : bounds) {
-                if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
-                    return true;
-                }
-            }
+            // create array type from raw component type and return its class
+            return Array.newInstance(rawComponentType, 0).getClass();
         }
 
-        if (type instanceof Class<?> || type instanceof ParameterizedType
-                || type instanceof GenericArrayType || type instanceof WildcardType) {
-            return false;
+        // (hand-waving) this is not the method you're looking for
+        if (type instanceof WildcardType) {
+            return null;
         }
 
-        throw new IllegalStateException("found an unhandled type: " + type);
+        throw new IllegalArgumentException("unknown type: " + type);
     }
 
     /**
-     * Finds the mapping for {@code type} in {@code typeVarAssigns}.
+     * Gets a map of the type arguments of a class in the context of {@code toClass}.
      *
-     * @param type the type to be replaced
-     * @param typeVarAssigns the map with type variables
-     * @return the replaced type
-     * @throws IllegalArgumentException if the type cannot be substituted
+     * @param cls the class in question
+     * @param toClass the context class
+     * @param subtypeVarAssigns a map with type variables
+     * @return the {@code Map} with type arguments
      */
-    private static Type substituteTypeVariables(final Type type, final Map<TypeVariable<?>, Type> typeVarAssigns) {
-        if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
-            final Type replacementType = typeVarAssigns.get(type);
+    private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, final Class<?> toClass,
+            final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
+        // make sure they're assignable
+        if (!isAssignable(cls, toClass)) {
+            return null;
+        }
 
-            if (replacementType == null) {
-                throw new IllegalArgumentException("missing assignment type for type variable "
-                        + type);
+        // can't work with primitives
+        if (cls.isPrimitive()) {
+            // both classes are primitives?
+            if (toClass.isPrimitive()) {
+                // dealing with widening here. No type arguments to be
+                // harvested with these two types.
+                return new HashMap<>();
             }
-            return replacementType;
+
+            // work with wrapper the wrapper class instead of the primitive
+            cls = ClassUtils.primitiveToWrapper(cls);
         }
-        return type;
+
+        // create a copy of the incoming map, or an empty one if it's null
+        final HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>()
+                : new HashMap<>(subtypeVarAssigns);
+
+        // has target class been reached?
+        if (toClass.equals(cls)) {
+            return typeVarAssigns;
+        }
+
+        // walk the inheritance hierarchy until the target class is reached
+        return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
     }
 
     /**
@@ -753,6 +864,61 @@ public class TypeUtils {
     }
 
     /**
+     * Gets a map of the type arguments of a parameterized type in the context of {@code toClass}.
+     *
+     * @param parameterizedType the parameterized type
+     * @param toClass the class
+     * @param subtypeVarAssigns a map with type variables
+     * @return the {@code Map} with type arguments
+     */
+    private static Map<TypeVariable<?>, Type> getTypeArguments(
+            final ParameterizedType parameterizedType, final Class<?> toClass,
+            final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
+        final Class<?> cls = getRawType(parameterizedType);
+
+        // make sure they're assignable
+        if (!isAssignable(cls, toClass)) {
+            return null;
+        }
+
+        final Type ownerType = parameterizedType.getOwnerType();
+        Map<TypeVariable<?>, Type> typeVarAssigns;
+
+        if (ownerType instanceof ParameterizedType) {
+            // get the owner type arguments first
+            final ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
+            typeVarAssigns = getTypeArguments(parameterizedOwnerType,
+                    getRawType(parameterizedOwnerType), subtypeVarAssigns);
+        } else {
+            // no owner, prep the type variable assignments map
+            typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>()
+                    : new HashMap<>(subtypeVarAssigns);
+        }
+
+        // get the subject parameterized type's arguments
+        final Type[] typeArgs = parameterizedType.getActualTypeArguments();
+        // and get the corresponding type variables from the raw class
+        final TypeVariable<?>[] typeParams = cls.getTypeParameters();
+
+        // map the arguments to their respective type variables
+        for (int i = 0; i < typeParams.length; i++) {
+            final Type typeArg = typeArgs[i];
+            typeVarAssigns.put(
+                    typeParams[i],
+                    typeVarAssigns.getOrDefault(typeArg, typeArg)
+            );
+        }
+
+        if (toClass.equals(cls)) {
+            // target class has been reached. Done.
+            return typeVarAssigns;
+        }
+
+        // walk the inheritance hierarchy until the target class is reached
+        return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
+    }
+
+    /**
      * Gets the type arguments of a class/interface based on a subtype. For
      * instance, this method will determine that both of the parameters for the
      * interface {@link Map} are {@link Object} for the subtype
@@ -844,628 +1010,539 @@ public class TypeUtils {
     }
 
     /**
-     * Gets a map of the type arguments of a parameterized type in the context of {@code toClass}.
-     *
-     * @param parameterizedType the parameterized type
-     * @param toClass the class
-     * @param subtypeVarAssigns a map with type variables
-     * @return the {@code Map} with type arguments
-     */
-    private static Map<TypeVariable<?>, Type> getTypeArguments(
-            final ParameterizedType parameterizedType, final Class<?> toClass,
-            final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
-        final Class<?> cls = getRawType(parameterizedType);
-
-        // make sure they're assignable
-        if (!isAssignable(cls, toClass)) {
-            return null;
-        }
-
-        final Type ownerType = parameterizedType.getOwnerType();
-        Map<TypeVariable<?>, Type> typeVarAssigns;
-
-        if (ownerType instanceof ParameterizedType) {
-            // get the owner type arguments first
-            final ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
-            typeVarAssigns = getTypeArguments(parameterizedOwnerType,
-                    getRawType(parameterizedOwnerType), subtypeVarAssigns);
-        } else {
-            // no owner, prep the type variable assignments map
-            typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>()
-                    : new HashMap<>(subtypeVarAssigns);
-        }
-
-        // get the subject parameterized type's arguments
-        final Type[] typeArgs = parameterizedType.getActualTypeArguments();
-        // and get the corresponding type variables from the raw class
-        final TypeVariable<?>[] typeParams = cls.getTypeParameters();
-
-        // map the arguments to their respective type variables
-        for (int i = 0; i < typeParams.length; i++) {
-            final Type typeArg = typeArgs[i];
-            typeVarAssigns.put(
-                    typeParams[i],
-                    typeVarAssigns.getOrDefault(typeArg, typeArg)
-            );
-        }
-
-        if (toClass.equals(cls)) {
-            // target class has been reached. Done.
-            return typeVarAssigns;
-        }
-
-        // walk the inheritance hierarchy until the target class is reached
-        return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
-    }
-
-    /**
-     * Gets a map of the type arguments of a class in the context of {@code toClass}.
+     * Tests whether the specified type denotes an array type.
      *
-     * @param cls the class in question
-     * @param toClass the context class
-     * @param subtypeVarAssigns a map with type variables
-     * @return the {@code Map} with type arguments
+     * @param type the type to be checked
+     * @return {@code true} if {@code type} is an array class or a {@link GenericArrayType}.
      */
-    private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, final Class<?> toClass,
-            final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
-        // make sure they're assignable
-        if (!isAssignable(cls, toClass)) {
-            return null;
-        }
-
-        // can't work with primitives
-        if (cls.isPrimitive()) {
-            // both classes are primitives?
-            if (toClass.isPrimitive()) {
-                // dealing with widening here. No type arguments to be
-                // harvested with these two types.
-                return new HashMap<>();
-            }
-
-            // work with wrapper the wrapper class instead of the primitive
-            cls = ClassUtils.primitiveToWrapper(cls);
-        }
-
-        // create a copy of the incoming map, or an empty one if it's null
-        final HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>()
-                : new HashMap<>(subtypeVarAssigns);
-
-        // has target class been reached?
-        if (toClass.equals(cls)) {
-            return typeVarAssigns;
-        }
-
-        // walk the inheritance hierarchy until the target class is reached
-        return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
+    public static boolean isArrayType(final Type type) {
+        return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
     }
 
     /**
-     * Tries to determine the type arguments of a class/interface based on a
-     * super parameterized type's type arguments. This method is the inverse of
-     * {@link #getTypeArguments(Type, Class)} which gets a class/interface's
-     * type arguments based on a subtype. It is far more limited in determining
-     * the type arguments for the subject class's type variables in that it can
-     * only determine those parameters that map from the subject {@link Class}
-     * object to the supertype.
-     * 
-     * <p>
-     * Example: {@link java.util.TreeSet
-     * TreeSet} sets its parameter as the parameter for
-     * {@link java.util.NavigableSet NavigableSet}, which in turn sets the
-     * parameter of {@link java.util.SortedSet}, which in turn sets the
-     * parameter of {@link Set}, which in turn sets the parameter of
-     * {@link java.util.Collection}, which in turn sets the parameter of
-     * {@link java.lang.Iterable}. Since {@code TreeSet}'s parameter maps
-     * (indirectly) to {@code Iterable}'s parameter, it will be able to
-     * determine that based on the super type {@code Iterable<? extends
-     * Map<Integer, ? extends Collection<?>>>}, the parameter of
-     * {@code TreeSet} is {@code ? extends Map<Integer, ? extends
-     * Collection<?>>}.
-     * </p>
+     * Tests if the subject type may be implicitly cast to the target class
+     * following the Java generics rules.
      *
-     * @param cls the class whose type parameters are to be determined, not {@code null}
-     * @param superType the super type from which {@code cls}'s type
-     * arguments are to be determined, not {@code null}
-     * @return a {@code Map} of the type assignments that could be determined
-     * for the type variables in each type in the inheritance hierarchy from
-     * {@code type} to {@code toClass} inclusive.
+     * @param type the subject type to be assigned to the target type
+     * @param toClass the target class
+     * @return {@code true} if {@code type} is assignable to {@code toClass}.
      */
-    public static Map<TypeVariable<?>, Type> determineTypeArguments(final Class<?> cls,
-            final ParameterizedType superType) {
-        Validate.notNull(cls, "cls is null");
-        Validate.notNull(superType, "superType is null");
+    private static boolean isAssignable(final Type type, final Class<?> toClass) {
+        if (type == null) {
+            // consistency with ClassUtils.isAssignable() behavior
+            return toClass == null || !toClass.isPrimitive();
+        }
 
-        final Class<?> superClass = getRawType(superType);
+        // only a null type can be assigned to null type which
+        // would have cause the previous to return true
+        if (toClass == null) {
+            return false;
+        }
 
-        // compatibility check
-        if (!isAssignable(cls, superClass)) {
-            return null;
+        // all types are assignable to themselves
+        if (toClass.equals(type)) {
+            return true;
         }
 
-        if (cls.equals(superClass)) {
-            return getTypeArguments(superType, superClass, null);
+        if (type instanceof Class<?>) {
+            // just comparing two classes
+            return ClassUtils.isAssignable((Class<?>) type, toClass);
         }
 
-        // get the next class in the inheritance hierarchy
-        final Type midType = getClosestParentType(cls, superClass);
+        if (type instanceof ParameterizedType) {
+            // only have to compare the raw type to the class
+            return isAssignable(getRawType((ParameterizedType) type), toClass);
+        }
 
-        // can only be a class or a parameterized type
-        if (midType instanceof Class<?>) {
-            return determineTypeArguments((Class<?>) midType, superType);
+        // *
+        if (type instanceof TypeVariable<?>) {
+            // if any of the bounds are assignable to the class, then the
+            // type is assignable to the class.
+            for (final Type bound : ((TypeVariable<?>) type).getBounds()) {
+                if (isAssignable(bound, toClass)) {
+                    return true;
+                }
+            }
+
+            return false;
         }
 
-        final ParameterizedType midParameterizedType = (ParameterizedType) midType;
-        final Class<?> midClass = getRawType(midParameterizedType);
-        // get the type variables of the mid class that map to the type
-        // arguments of the super class
-        final Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superType);
-        // map the arguments of the mid type to the class type variables
-        mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
+        // the only classes to which a generic array type can be assigned
+        // are class Object and array classes
+        if (type instanceof GenericArrayType) {
+            return toClass.equals(Object.class)
+                    || toClass.isArray()
+                    && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass
+                            .getComponentType());
+        }
 
-        return typeVarAssigns;
+        // wildcard types are not assignable to a class (though one would think
+        // "? super Object" would be assignable to Object)
+        if (type instanceof WildcardType) {
+            return false;
+        }
+
+        throw new IllegalStateException("found an unhandled type: " + type);
     }
 
     /**
-     * Maps type variables.
+     * Tests if the subject type may be implicitly cast to the target
+     * generic array type following the Java generics rules.
      *
-     * @param <T> the generic type of the class in question
-     * @param cls the class in question
-     * @param parameterizedType the parameterized type
-     * @param typeVarAssigns the map to be filled
+     * @param type the subject type to be assigned to the target type
+     * @param toGenericArrayType the target generic array type
+     * @param typeVarAssigns a map with type variables
+     * @return {@code true} if {@code type} is assignable to
+     * {@code toGenericArrayType}.
      */
-    private static <T> void mapTypeVariablesToArguments(final Class<T> cls,
-            final ParameterizedType parameterizedType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
-        // capture the type variables from the owner type that have assignments
-        final Type ownerType = parameterizedType.getOwnerType();
-
-        if (ownerType instanceof ParameterizedType) {
-            // recursion to make sure the owner's owner type gets processed
-            mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
+    private static boolean isAssignable(final Type type, final GenericArrayType toGenericArrayType,
+            final Map<TypeVariable<?>, Type> typeVarAssigns) {
+        if (type == null) {
+            return true;
         }
 
-        // parameterizedType is a generic interface/class (or it's in the owner
-        // hierarchy of said interface/class) implemented/extended by the class
-        // cls. Find out which type variables of cls are type arguments of
-        // parameterizedType:
-        final Type[] typeArgs = parameterizedType.getActualTypeArguments();
+        // only a null type can be assigned to null type which
+        // would have cause the previous to return true
+        if (toGenericArrayType == null) {
+            return false;
+        }
 
-        // of the cls's type variables that are arguments of parameterizedType,
-        // find out which ones can be determined from the super type's arguments
-        final TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
+        // all types are assignable to themselves
+        if (toGenericArrayType.equals(type)) {
+            return true;
+        }
 
-        // use List view of type parameters of cls so the contains() method can be used:
-        final List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls
-                .getTypeParameters());
+        final Type toComponentType = toGenericArrayType.getGenericComponentType();
 
-        for (int i = 0; i < typeArgs.length; i++) {
-            final TypeVariable<?> typeVar = typeVars[i];
-            final Type typeArg = typeArgs[i];
+        if (type instanceof Class<?>) {
+            final Class<?> cls = (Class<?>) type;
 
-            // argument of parameterizedType is a type variable of cls
-            if (typeVarList.contains(typeArg)
-            // type variable of parameterizedType has an assignment in
-                    // the super type.
-                    && typeVarAssigns.containsKey(typeVar)) {
-                // map the assignment to the cls's type variable
-                typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
-            }
+            // compare the component types
+            return cls.isArray()
+                    && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
         }
-    }
-
-    /**
-     * Gets the closest parent type to the
-     * super class specified by {@code superClass}.
-     *
-     * @param cls the class in question
-     * @param superClass the super class
-     * @return the closes parent type
-     */
-    private static Type getClosestParentType(final Class<?> cls, final Class<?> superClass) {
-        // only look at the interfaces if the super class is also an interface
-        if (superClass.isInterface()) {
-            // get the generic interfaces of the subject class
-            final Type[] interfaceTypes = cls.getGenericInterfaces();
-            // will hold the best generic interface match found
-            Type genericInterface = null;
 
-            // find the interface closest to the super class
-            for (final Type midType : interfaceTypes) {
-                Class<?> midClass = null;
+        if (type instanceof GenericArrayType) {
+            // compare the component types
+            return isAssignable(((GenericArrayType) type).getGenericComponentType(),
+                    toComponentType, typeVarAssigns);
+        }
 
-                if (midType instanceof ParameterizedType) {
-                    midClass = getRawType((ParameterizedType) midType);
-                } else if (midType instanceof Class<?>) {
-                    midClass = (Class<?>) midType;
-                } else {
-                    throw new IllegalStateException("Unexpected generic"
-                            + " interface type found: " + midType);
+        if (type instanceof WildcardType) {
+            // so long as one of the upper bounds is assignable, it's good
+            for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
+                if (isAssignable(bound, toGenericArrayType)) {
+                    return true;
                 }
+            }
 
-                // check if this interface is further up the inheritance chain
-                // than the previously found match
-                if (isAssignable(midClass, superClass)
-                        && isAssignable(genericInterface, (Type) midClass)) {
-                    genericInterface = midType;
+            return false;
+        }
+
+        if (type instanceof TypeVariable<?>) {
+            // probably should remove the following logic and just return false.
+            // type variables cannot specify arrays as bounds.
+            for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
+                if (isAssignable(bound, toGenericArrayType)) {
+                    return true;
                 }
             }
 
-            // found a match?
-            if (genericInterface != null) {
-                return genericInterface;
-            }
+            return false;
         }
 
-        // none of the interfaces were descendants of the target class, so the
-        // super class has to be one, instead
-        return cls.getGenericSuperclass();
-    }
-
-    /**
-     * Tests if the given value can be assigned to the target type
-     * following the Java generics rules.
-     *
-     * @param value the value to be checked
-     * @param type the target type
-     * @return {@code true} if {@code value} is an instance of {@code type}.
-     */
-    public static boolean isInstance(final Object value, final Type type) {
-        if (type == null) {
+        if (type instanceof ParameterizedType) {
+            // the raw type of a parameterized type is never an array or
+            // generic array, otherwise the declaration would look like this:
+            // Collection[]< ? extends String > collection;
             return false;
         }
 
-        return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()
-                : isAssignable(value.getClass(), type, null);
+        throw new IllegalStateException("found an unhandled type: " + type);
     }
 
     /**
-     * Strips out the redundant upper bound types in type
-     * variable types and wildcard types (or it would with wildcard types if
-     * multiple upper bounds were allowed).
-     * 
-     * <p>
-     * Example, with the variable type declaration:
-     * </p>
-     *
-     * <pre>&lt;K extends java.util.Collection&lt;String&gt; &amp;
-     * java.util.List&lt;String&gt;&gt;</pre>
-     *
-     * <p>
-     * since {@code List} is a subinterface of {@code Collection},
-     * this method will return the bounds as if the declaration had been:
-     * </p>
-     *
-     * <pre>&lt;K extends java.util.List&lt;String&gt;&gt;</pre>
+     * Tests if the subject type may be implicitly cast to the target
+     * parameterized type following the Java generics rules.
      *
-     * @param bounds an array of types representing the upper bounds of either
-     * {@link WildcardType} or {@link TypeVariable}, not {@code null}.
-     * @return an array containing the values from {@code bounds} minus the
-     * redundant types.
+     * @param type the subject type to be assigned to the target type
+     * @param toParameterizedType the target parameterized type
+     * @param typeVarAssigns a map with type variables
+     * @return {@code true} if {@code type} is assignable to {@code toType}.
      */
-    public static Type[] normalizeUpperBounds(final Type[] bounds) {
-        Validate.notNull(bounds, "null value specified for bounds array");
-        // don't bother if there's only one (or none) type
-        if (bounds.length < 2) {
-            return bounds;
+    private static boolean isAssignable(final Type type, final ParameterizedType toParameterizedType,
+            final Map<TypeVariable<?>, Type> typeVarAssigns) {
+        if (type == null) {
+            return true;
+        }
+
+        // only a null type can be assigned to null type which
+        // would have cause the previous to return true
+        if (toParameterizedType == null) {
+            return false;
         }
 
-        final Set<Type> types = new HashSet<>(bounds.length);
+        // all types are assignable to themselves
+        if (toParameterizedType.equals(type)) {
+            return true;
+        }
 
-        for (final Type type1 : bounds) {
-            boolean subtypeFound = false;
+        // get the target type's raw type
+        final Class<?> toClass = getRawType(toParameterizedType);
+        // get the subject type's type arguments including owner type arguments
+        // and supertype arguments up to and including the target class.
+        final Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
 
-            for (final Type type2 : bounds) {
-                if (type1 != type2 && isAssignable(type2, type1, null)) {
-                    subtypeFound = true;
-                    break;
-                }
+        // null means the two types are not compatible
+        if (fromTypeVarAssigns == null) {
+            return false;
+        }
+
+        // compatible types, but there's no type arguments. this is equivalent
+        // to comparing Map< ?, ? > to Map, and raw types are always assignable
+        // to parameterized types.
+        if (fromTypeVarAssigns.isEmpty()) {
+            return true;
+        }
+
+        // get the target type's type arguments including owner type arguments
+        final Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType,
+                toClass, typeVarAssigns);
+
+        // now to check each type argument
+        for (final TypeVariable<?> var : toTypeVarAssigns.keySet()) {
+            final Type toTypeArg = unrollVariableAssignments(var, toTypeVarAssigns);
+            final Type fromTypeArg = unrollVariableAssignments(var, fromTypeVarAssigns);
+
+            if (toTypeArg == null && fromTypeArg instanceof Class) {
+                continue;
             }
 
-            if (!subtypeFound) {
-                types.add(type1);
+            // parameters must either be absent from the subject type, within
+            // the bounds of the wildcard type, or be an exact match to the
+            // parameters of the target type.
+            if (fromTypeArg != null
+                    && !toTypeArg.equals(fromTypeArg)
+                    && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg,
+                            typeVarAssigns))) {
+                return false;
             }
         }
-
-        return types.toArray(ArrayUtils.EMPTY_TYPE_ARRAY);
+        return true;
     }
 
     /**
-     * Gets an array containing the sole type of {@link Object} if
-     * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it
-     * returns the result of {@link TypeVariable#getBounds()} passed into
-     * {@link #normalizeUpperBounds}.
+     * Tests if the subject type may be implicitly cast to the target type
+     * following the Java generics rules. If both types are {@link Class}
+     * objects, the method returns the result of
+     * {@link ClassUtils#isAssignable(Class, Class)}.
      *
-     * @param typeVariable the subject type variable, not {@code null}
-     * @return a non-empty array containing the bounds of the type variable.
+     * @param type the subject type to be assigned to the target type
+     * @param toType the target type
+     * @return {@code true} if {@code type} is assignable to {@code toType}.
      */
-    public static Type[] getImplicitBounds(final TypeVariable<?> typeVariable) {
-        Validate.notNull(typeVariable, "typeVariable is null");
-        final Type[] bounds = typeVariable.getBounds();
-
-        return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
+    public static boolean isAssignable(final Type type, final Type toType) {
+        return isAssignable(type, toType, null);
     }
 
     /**
-     * Gets an array containing the sole value of {@link Object} if
-     * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise,
-     * it returns the result of {@link WildcardType#getUpperBounds()}
-     * passed into {@link #normalizeUpperBounds}.
+     * Tests if the subject type may be implicitly cast to the target type
+     * following the Java generics rules.
      *
-     * @param wildcardType the subject wildcard type, not {@code null}
-     * @return a non-empty array containing the upper bounds of the wildcard
-     * type.
+     * @param type the subject type to be assigned to the target type
+     * @param toType the target type
+     * @param typeVarAssigns optional map of type variable assignments
+     * @return {@code true} if {@code type} is assignable to {@code toType}.
      */
-    public static Type[] getImplicitUpperBounds(final WildcardType wildcardType) {
-        Validate.notNull(wildcardType, "wildcardType is null");
-        final Type[] bounds = wildcardType.getUpperBounds();
+    private static boolean isAssignable(final Type type, final Type toType,
+            final Map<TypeVariable<?>, Type> typeVarAssigns) {
+        if (toType == null || toType instanceof Class<?>) {
+            return isAssignable(type, (Class<?>) toType);
+        }
 
-        return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
-    }
+        if (toType instanceof ParameterizedType) {
+            return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
+        }
 
-    /**
-     * Gets an array containing a single value of {@code null} if
-     * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise,
-     * it returns the result of {@link WildcardType#getLowerBounds()}.
-     *
-     * @param wildcardType the subject wildcard type, not {@code null}
-     * @return a non-empty array containing the lower bounds of the wildcard
-     * type.
-     */
-    public static Type[] getImplicitLowerBounds(final WildcardType wildcardType) {
-        Validate.notNull(wildcardType, "wildcardType is null");
-        final Type[] bounds = wildcardType.getLowerBounds();
+        if (toType instanceof GenericArrayType) {
+            return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
+        }
 
-        return bounds.length == 0 ? new Type[] { null } : bounds;
+        if (toType instanceof WildcardType) {
+            return isAssignable(type, (WildcardType) toType, typeVarAssigns);
+        }
+
+        if (toType instanceof TypeVariable<?>) {
+            return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
+        }
+
+        throw new IllegalStateException("found an unhandled type: " + toType);
     }
 
     /**
-     * Determines whether or not specified types satisfy the bounds of their
-     * mapped type variables. When a type parameter extends another (such as
-     * {@code <T, S extends T>}), uses another as a type parameter (such as
-     * {@code <T, S extends Comparable>>}), or otherwise depends on
-     * another type variable to be specified, the dependencies must be included
-     * in {@code typeVarAssigns}.
+     * Tests if the subject type may be implicitly cast to the target type
+     * variable following the Java generics rules.
      *
-     * @param typeVarAssigns specifies the potential types to be assigned to the
-     * type variables, not {@code null}.
-     * @return whether or not the types can be assigned to their respective type
-     * variables.
+     * @param type the subject type to be assigned to the target type
+     * @param toTypeVariable the target type variable
+     * @param typeVarAssigns a map with type variables
+     * @return {@code true} if {@code type} is assignable to
+     * {@code toTypeVariable}.
      */
-    public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVarAssigns) {
-        Validate.notNull(typeVarAssigns, "typeVarAssigns is null");
-        // all types must be assignable to all the bounds of their mapped
-        // type variable.
-        for (final Map.Entry<TypeVariable<?>, Type> entry : typeVarAssigns.entrySet()) {
-            final TypeVariable<?> typeVar = entry.getKey();
-            final Type type = entry.getValue();
+    private static boolean isAssignable(final Type type, final TypeVariable<?> toTypeVariable,
+            final Map<TypeVariable<?>, Type> typeVarAssigns) {
+        if (type == null) {
+            return true;
+        }
 
-            for (final Type bound : getImplicitBounds(typeVar)) {
-                if (!isAssignable(type, substituteTypeVariables(bound, typeVarAssigns),
-                        typeVarAssigns)) {
-                    return false;
+        // only a null type can be assigned to null type which
+        // would have cause the previous to return true
+        if (toTypeVariable == null) {
+            return false;
+        }
+
+        // all types are assignable to themselves
+        if (toTypeVariable.equals(type)) {
+            return true;
+        }
+
+        if (type instanceof TypeVariable<?>) {
+            // a type variable is assignable to another type variable, if
+            // and only if the former is the latter, extends the latter, or
+            // is otherwise a descendant of the latter.
+            final Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
+
+            for (final Type bound : bounds) {
+                if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
+                    return true;
                 }
             }
         }
-        return true;
-    }
-
-    /**
-     * Transforms the passed in type to a {@link Class} object. Type-checking method of convenience.
-     *
-     * @param parameterizedType the type to be converted
-     * @return the corresponding {@code Class} object
-     * @throws IllegalStateException if the conversion fails
-     */
-    private static Class<?> getRawType(final ParameterizedType parameterizedType) {
-        final Type rawType = parameterizedType.getRawType();
 
-        // check if raw type is a Class object
-        // not currently necessary, but since the return type is Type instead of
-        // Class, there's enough reason to believe that future versions of Java
-        // may return other Type implementations. And type-safety checking is
-        // rarely a bad idea.
-        if (!(rawType instanceof Class<?>)) {
-            throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType);
+        if (type instanceof Class<?> || type instanceof ParameterizedType
+                || type instanceof GenericArrayType || type instanceof WildcardType) {
+            return false;
         }
 
-        return (Class<?>) rawType;
+        throw new IllegalStateException("found an unhandled type: " + type);
     }
 
     /**
-     * Gets the raw type of a Java type, given its context. Primarily for use
-     * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
-     * not know the runtime type of {@code type}: if you know you have a
-     * {@link Class} instance, it is already raw; if you know you have a
-     * {@link ParameterizedType}, its raw type is only a method call away.
+     * Tests if the subject type may be implicitly cast to the target
+     * wildcard type following the Java generics rules.
      *
-     * @param type to resolve
-     * @param assigningType type to be resolved against
-     * @return the resolved {@link Class} object or {@code null} if
-     * the type could not be resolved
+     * @param type the subject type to be assigned to the target type
+     * @param toWildcardType the target wildcard type
+     * @param typeVarAssigns a map with type variables
+     * @return {@code true} if {@code type} is assignable to
+     * {@code toWildcardType}.
      */
-    public static Class<?> getRawType(final Type type, final Type assigningType) {
-        if (type instanceof Class<?>) {
-            // it is raw, no problem
-            return (Class<?>) type;
+    private static boolean isAssignable(final Type type, final WildcardType toWildcardType,
+            final Map<TypeVariable<?>, Type> typeVarAssigns) {
+        if (type == null) {
+            return true;
         }
 
-        if (type instanceof ParameterizedType) {
-            // simple enough to get the raw type of a ParameterizedType
-            return getRawType((ParameterizedType) type);
+        // only a null type can be assigned to null type which
+        // would have cause the previous to return true
+        if (toWildcardType == null) {
+            return false;
         }
 
-        if (type instanceof TypeVariable<?>) {
-            if (assigningType == null) {
-                return null;
-            }
+        // all types are assignable to themselves
+        if (toWildcardType.equals(type)) {
+            return true;
+        }
 
-            // get the entity declaring this type variable
-            final Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
+        final Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
+        final Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
 
-            // can't get the raw type of a method- or constructor-declared type
-            // variable
-            if (!(genericDeclaration instanceof Class<?>)) {
-                return null;
-            }
+        if (type instanceof WildcardType) {
+            final WildcardType wildcardType = (WildcardType) type;
+            final Type[] upperBounds = getImplicitUpperBounds(wildcardType);
+            final Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
 
-            // get the type arguments for the declaring class/interface based
-            // on the enclosing type
-            final Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType,
-                    (Class<?>) genericDeclaration);
+            for (Type toBound : toUpperBounds) {
+                // if there are assignments for unresolved type variables,
+                // now's the time to substitute them.
+                toBound = substituteTypeVariables(toBound, typeVarAssigns);
 
-            // enclosingType has to be a subclass (or subinterface) of the
-            // declaring type
-            if (typeVarAssigns == null) {
-                return null;
+                // each upper bound of the subject type has to be assignable to
+                // each
+                // upper bound of the target type
+                for (final Type bound : upperBounds) {
+                    if (!isAssignable(bound, toBound, typeVarAssigns)) {
+                        return false;
+                    }
+                }
             }
 
-            // get the argument assigned to this type variable
-            final Type typeArgument = typeVarAssigns.get(type);
+            for (Type toBound : toLowerBounds) {
+                // if there are assignments for unresolved type variables,
+                // now's the time to substitute them.
+                toBound = substituteTypeVariables(toBound, typeVarAssigns);
 
-            if (typeArgument == null) {
-                return null;
+                // each lower bound of the target type has to be assignable to
+                // each
+                // lower bound of the subject type
+                for (final Type bound : lowerBounds) {
+                    if (!isAssignable(toBound, bound, typeVarAssigns)) {
+                        return false;
+                    }
+                }
             }
-
-            // get the argument for this type variable
-            return getRawType(typeArgument, assigningType);
+            return true;
         }
 
-        if (type instanceof GenericArrayType) {
-            // get raw component type
-            final Class<?> rawComponentType = getRawType(((GenericArrayType) type)
-                    .getGenericComponentType(), assigningType);
-
-            // create array type from raw component type and return its class
-            return Array.newInstance(rawComponentType, 0).getClass();
+        for (final Type toBound : toUpperBounds) {
+            // if there are assignments for unresolved type variables,
+            // now's the time to substitute them.
+            if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns),
+                    typeVarAssigns)) {
+                return false;
+            }
         }
 
-        // (hand-waving) this is not the method you're looking for
-        if (type instanceof WildcardType) {
-            return null;
+        for (final Type toBound : toLowerBounds) {
+            // if there are assignments for unresolved type variables,
+            // now's the time to substitute them.
+            if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type,
+                    typeVarAssigns)) {
+                return false;
+            }
         }
-
-        throw new IllegalArgumentException("unknown type: " + type);
-    }
-
-    /**
-     * Tests whether the specified type denotes an array type.
-     *
-     * @param type the type to be checked
-     * @return {@code true} if {@code type} is an array class or a {@link GenericArrayType}.
-     */
-    public static boolean isArrayType(final Type type) {
-        return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
+        return true;
     }
 
     /**
-     * Gets the array component type of {@code type}.
+     * Tests if the given value can be assigned to the target type
+     * following the Java generics rules.
      *
-     * @param type the type to be checked
-     * @return component type or null if type is not an array type
+     * @param value the value to be checked
+     * @param type the target type
+     * @return {@code true} if {@code value} is an instance of {@code type}.
      */
-    public static Type getArrayComponentType(final Type type) {
-        if (type instanceof Class<?>) {
-            final Class<?> cls = (Class<?>) type;
-            return cls.isArray() ? cls.getComponentType() : null;
-        }
-        if (type instanceof GenericArrayType) {
-            return ((GenericArrayType) type).getGenericComponentType();
+    public static boolean isInstance(final Object value, final Type type) {
+        if (type == null) {
+            return false;
         }
-        return null;
+
+        return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()
+                : isAssignable(value.getClass(), type, null);
     }
 
     /**
-     * Gets a type representing {@code type} with variable assignments "unrolled."
+     * Maps type variables.
      *
-     * @param typeArguments as from {@link TypeUtils#getTypeArguments(Type, Class)}
-     * @param type the type to unroll variable assignments for
-     * @return Type
-     * @since 3.2
+     * @param <T> the generic type of the class in question
+     * @param cls the class in question
+     * @param parameterizedType the parameterized type
+     * @param typeVarAssigns the map to be filled
      */
-    public static Type unrollVariables(Map<TypeVariable<?>, Type> typeArguments, final Type type) {
-        if (typeArguments == null) {
-            typeArguments = Collections.emptyMap();
-        }
-        if (containsTypeVariables(type)) {
-            if (type instanceof TypeVariable<?>) {
-                return unrollVariables(typeArguments, typeArguments.get(type));
-            }
-            if (type instanceof ParameterizedType) {
-                final ParameterizedType p = (ParameterizedType) type;
-                final Map<TypeVariable<?>, Type> parameterizedTypeArguments;
-                if (p.getOwnerType() == null) {
-                    parameterizedTypeArguments = typeArguments;
-                } else {
-                    parameterizedTypeArguments = new HashMap<>(typeArguments);
-                    parameterizedTypeArguments.putAll(getTypeArguments(p));
-                }
-                final Type[] args = p.getActualTypeArguments();
-                for (int i = 0; i < args.length; i++) {
-                    final Type unrolled = unrollVariables(parameterizedTypeArguments, args[i]);
-                    if (unrolled != null) {
-                        args[i] = unrolled;
-                    }
-                }
-                return parameterizeWithOwner(p.getOwnerType(), (Class<?>) p.getRawType(), args);
-            }
-            if (type instanceof WildcardType) {
-                final WildcardType wild = (WildcardType) type;
-                return wildcardType().withUpperBounds(unrollBounds(typeArguments, wild.getUpperBounds()))
-                    .withLowerBounds(unrollBounds(typeArguments, wild.getLowerBounds())).build();
-            }
+    private static <T> void mapTypeVariablesToArguments(final Class<T> cls,
+            final ParameterizedType parameterizedType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
+        // capture the type variables from the owner type that have assignments
+        final Type ownerType = parameterizedType.getOwnerType();
+
+        if (ownerType instanceof ParameterizedType) {
+            // recursion to make sure the owner's owner type gets processed
+            mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
         }
-        return type;
-    }
 
-    /**
-     * Unrolls variables in a type bounds array.
-     *
-     * @param typeArguments assignments {@link Map}
-     * @param bounds in which to expand variables
-     * @return {@code bounds} with any variables reassigned
-     * @since 3.2
-     */
-    private static Type[] unrollBounds(final Map<TypeVariable<?>, Type> typeArguments, final Type[] bounds) {
-        Type[] result = bounds;
-        int i = 0;
-        for (; i < result.length; i++) {
-            final Type unrolled = unrollVariables(typeArguments, result[i]);
-            if (unrolled == null) {
-                result = ArrayUtils.remove(result, i--);
-            } else {
-                result[i] = unrolled;
+        // parameterizedType is a generic interface/class (or it's in the owner
+        // hierarchy of said interface/class) implemented/extended by the class
+        // cls. Find out which type variables of cls are type arguments of
+        // parameterizedType:
+        final Type[] typeArgs = parameterizedType.getActualTypeArguments();
+
+        // of the cls's type variables that are arguments of parameterizedType,
+        // find out which ones can be determined from the super type's arguments
+        final TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
+
+        // use List view of type parameters of cls so the contains() method can be used:
+        final List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls
+                .getTypeParameters());
+
+        for (int i = 0; i < typeArgs.length; i++) {
+            final TypeVariable<?> typeVar = typeVars[i];
+            final Type typeArg = typeArgs[i];
+
+            // argument of parameterizedType is a type variable of cls
+            if (typeVarList.contains(typeArg)
+            // type variable of parameterizedType has an assignment in
+                    // the super type.
+                    && typeVarAssigns.containsKey(typeVar)) {
+                // map the assignment to the cls's type variable
+                typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
             }
         }
-        return result;
     }
 
     /**
-     * Tests, recursively, whether any of the type parameters associated with {@code type} are bound to variables.
+     * Strips out the redundant upper bound types in type
+     * variable types and wildcard types (or it would with wildcard types if
+     * multiple upper bounds were allowed).
+     * 
+     * <p>
+     * Example, with the variable type declaration:
+     * </p>
      *
-     * @param type the type to check for type variables
-     * @return boolean
-     * @since 3.2
+     * <pre>&lt;K extends java.util.Collection&lt;String&gt; &amp;
+     * java.util.List&lt;String&gt;&gt;</pre>
+     *
+     * <p>
+     * since {@code List} is a subinterface of {@code Collection},
+     * this method will return the bounds as if the declaration had been:
+     * </p>
+     *
+     * <pre>&lt;K extends java.util.List&lt;String&gt;&gt;</pre>
+     *
+     * @param bounds an array of types representing the upper bounds of either
+     * {@link WildcardType} or {@link TypeVariable}, not {@code null}.
+     * @return an array containing the values from {@code bounds} minus the
+     * redundant types.
      */
-    public static boolean containsTypeVariables(final Type type) {
-        if (type instanceof TypeVariable<?>) {
-            return true;
-        }
-        if (type instanceof Class<?>) {
-            return ((Class<?>) type).getTypeParameters().length > 0;
+    public static Type[] normalizeUpperBounds(final Type[] bounds) {
+        Validate.notNull(bounds, "null value specified for bounds array");
+        // don't bother if there's only one (or none) type
+        if (bounds.length < 2) {
+            return bounds;
         }
-        if (type instanceof ParameterizedType) {
-            for (final Type arg : ((ParameterizedType) type).getActualTypeArguments()) {
-                if (containsTypeVariables(arg)) {
-                    return true;
+
+        final Set<Type> types = new HashSet<>(bounds.length);
+
+        for (final Type type1 : bounds) {
+            boolean subtypeFound = false;
+
+            for (final Type type2 : bounds) {
+                if (type1 != type2 && isAssignable(type2, type1, null)) {
+                    subtypeFound = true;
+                    break;
                 }
             }
-            return false;
-        }
-        if (type instanceof WildcardType) {
-            final WildcardType wild = (WildcardType) type;
-            return containsTypeVariables(getImplicitLowerBounds(wild)[0])
-                || containsTypeVariables(getImplicitUpperBounds(wild)[0]);
+
+            if (!subtypeFound) {
+                types.add(type1);
+            }
         }
-        return false;
+
+        return types.toArray(ArrayUtils.EMPTY_TYPE_ARRAY);
+    }
+
+    /**
+     * Creates a parameterized type instance.
+     *
+     * @param rawClass the raw class to create a parameterized type instance for
+     * @param typeArgMappings the mapping used for parameterization
+     * @return {@link ParameterizedType}
+     * @since 3.2
+     */
+    public static final ParameterizedType parameterize(final Class<?> rawClass,
+        final Map<TypeVariable<?>, Type> typeArgMappings) {
+        Validate.notNull(rawClass, "raw class is null");
+        Validate.notNull(typeArgMappings, "typeArgMappings is null");
+        return parameterizeWithOwner(null, rawClass,
+            extractTypeArgumentsFrom(typeArgMappings, rawClass.getTypeParameters()));
     }
 
     /**
@@ -1481,18 +1558,54 @@ public class TypeUtils {
     }
 
     /**
+     * Formats a {@link ParameterizedType} as a {@link String}.
+     *
+     * @param parameterizedType {@code ParameterizedType} to format
+     * @return String
+     * @since 3.2
+     */
+    private static String parameterizedTypeToString(final ParameterizedType parameterizedType) {
+        final StringBuilder builder = new StringBuilder();
+
+        final Type useOwner = parameterizedType.getOwnerType();
+        final Class<?> raw = (Class<?>) parameterizedType.getRawType();
+
+        if (useOwner == null) {
+            builder.append(raw.getName());
+        } else {
+            if (useOwner instanceof Class<?>) {
+                builder.append(((Class<?>) useOwner).getName());
+            } else {
+                builder.append(useOwner.toString());
+            }
+            builder.append('.').append(raw.getSimpleName());
+        }
+
+        final int[] recursiveTypeIndexes = findRecursiveTypes(parameterizedType);
+
+        if (recursiveTypeIndexes.length > 0) {
+            appendRecursiveTypes(builder, recursiveTypeIndexes, parameterizedType.getActualTypeArguments());
+        } else {
+            appendAllTo(builder.append('<'), ", ", parameterizedType.getActualTypeArguments()).append('>');
+        }
+
+        return builder.toString();
+    }
+
+    /**
      * Creates a parameterized type instance.
      *
+     * @param owner the owning type
      * @param rawClass the raw class to create a parameterized type instance for
      * @param typeArgMappings the mapping used for parameterization
      * @return {@link ParameterizedType}
      * @since 3.2
      */
-    public static final ParameterizedType parameterize(final Class<?> rawClass,
+    public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass,
         final Map<TypeVariable<?>, Type> typeArgMappings) {
         Validate.notNull(rawClass, "raw class is null");
         Validate.notNull(typeArgMappings, "typeArgMappings is null");
-        return parameterizeWithOwner(null, rawClass,
+        return parameterizeWithOwner(owner, rawClass,
             extractTypeArgumentsFrom(typeArgMappings, rawClass.getTypeParameters()));
     }
 
@@ -1529,179 +1642,24 @@ public class TypeUtils {
     }
 
     /**
-     * Creates a parameterized type instance.
-     *
-     * @param owner the owning type
-     * @param rawClass the raw class to create a parameterized type instance for
-     * @param typeArgMappings the mapping used for parameterization
-     * @return {@link ParameterizedType}
-     * @since 3.2
-     */
-    public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass,
-        final Map<TypeVariable<?>, Type> typeArgMappings) {
-        Validate.notNull(rawClass, "raw class is null");
-        Validate.notNull(typeArgMappings, "typeArgMappings is null");
-        return parameterizeWithOwner(owner, rawClass,
-            extractTypeArgumentsFrom(typeArgMappings, rawClass.getTypeParameters()));
-    }
-
-    /**
-     * Helper method to establish the formal parameters for a parameterized type.
-     *
-     * @param mappings map containing the assignments
-     * @param variables expected map keys
-     * @return array of map values corresponding to specified keys
-     */
-    private static Type[] extractTypeArgumentsFrom(final Map<TypeVariable<?>, Type> mappings, final TypeVariable<?>[] variables) {
-        final Type[] result = new Type[variables.length];
-        int index = 0;
-        for (final TypeVariable<?> var : variables) {
-            Validate.isTrue(mappings.containsKey(var), "missing argument mapping for %s", toString(var));
-            result[index++] = mappings.get(var);
-        }
-        return result;
-    }
-
-    /**
-     * Gets a {@link WildcardTypeBuilder}.
-     *
-     * @return {@link WildcardTypeBuilder}
-     * @since 3.2
-     */
-    public static WildcardTypeBuilder wildcardType() {
-        return new WildcardTypeBuilder();
-    }
-
-    /**
-     * Creates a generic array type instance.
-     *
-     * @param componentType the type of the elements of the array. For example the component type of {@code boolean[]}
-     *                      is {@code boolean}
-     * @return {@link GenericArrayType}
-     * @since 3.2
-     */
-    public static GenericArrayType genericArrayType(final Type componentType) {
-        return new GenericArrayTypeImpl(Validate.notNull(componentType, "componentType is null"));
-    }
-
-    /**
-     * Tests equality of types.
-     *
-     * @param type1 the first type
-     * @param type2 the second type
-     * @return boolean
-     * @since 3.2
-     */
-    public static boolean equals(final Type type1, final Type type2) {
-        if (Objects.equals(type1, type2)) {
-            return true;
-        }
-        if (type1 instanceof ParameterizedType) {
-            return equals((ParameterizedType) type1, type2);
-        }
-        if (type1 instanceof GenericArrayType) {
-            return equals((GenericArrayType) type1, type2);
-        }
-        if (type1 instanceof WildcardType) {
-            return equals((WildcardType) type1, type2);
-        }
-        return false;
-    }
-
-    /**
-     * Tests whether {@code t} equals {@code p}.
-     *
-     * @param parameterizedType LHS
-     * @param type RHS
-     * @return boolean
-     * @since 3.2
-     */
-    private static boolean equals(final ParameterizedType parameterizedType, final Type type) {
-        if (type instanceof ParameterizedType) {
-            final ParameterizedType other = (ParameterizedType) type;
-            if (equals(parameterizedType.getRawType(), other.getRawType())
-                && equals(parameterizedType.getOwnerType(), other.getOwnerType())) {
-                return equals(parameterizedType.getActualTypeArguments(), other.getActualTypeArguments());
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Tests whether {@code t} equals {@code a}.
-     *
-     * @param genericArrayType LHS
-     * @param type RHS
-     * @return boolean
-     * @since 3.2
-     */
-    private static boolean equals(final GenericArrayType genericArrayType, final Type type) {
-        return type instanceof GenericArrayType
-            && equals(genericArrayType.getGenericComponentType(), ((GenericArrayType) type).getGenericComponentType());
-    }
-
-    /**
-     * Tests whether {@code t} equals {@code w}.
+     * Finds the mapping for {@code type} in {@code typeVarAssigns}.
      *
-     * @param wildcardType LHS
-     * @param type RHS
-     * @return boolean
-     * @since 3.2
+     * @param type the type to be replaced
+     * @param typeVarAssigns the map with type variables
+     * @return the replaced type
+     * @throws IllegalArgumentException if the type cannot be substituted
      */
-    private static boolean equals(final WildcardType wildcardType, final Type type) {
-        if (type instanceof WildcardType) {
-            final WildcardType other = (WildcardType) type;
-            return equals(getImplicitLowerBounds(wildcardType), getImplicitLowerBounds(other))
-                && equals(getImplicitUpperBounds(wildcardType), getImplicitUpperBounds(other));
-        }
-        return false;
-    }
+    private static Type substituteTypeVariables(final Type type, final Map<TypeVariable<?>, Type> typeVarAssigns) {
+        if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
+            final Type replacementType = typeVarAssigns.get(type);
 
-    /**
-     * Tests whether {@code t1} equals {@code t2}.
-     *
-     * @param type1 LHS
-     * @param type2 RHS
-     * @return boolean
-     * @since 3.2
-     */
-    private static boolean equals(final Type[] type1, final Type[] type2) {
-        if (type1.length == type2.length) {
-            for (int i = 0; i < type1.length; i++) {
-                if (!equals(type1[i], type2[i])) {
-                    return false;
-                }
+            if (replacementType == null) {
+                throw new IllegalArgumentException("missing assignment type for type variable "
+                        + type);
             }
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Formats a given type as a Java-esque String.
-     *
-     * @param type the type to create a String representation for, not {@code null}
-     * @return String
-     * @since 3.2
-     */
-    public static String toString(final Type type) {
-        Validate.notNull(type);
-        if (type instanceof Class<?>) {
-            return classToString((Class<?>) type);
-        }
-        if (type instanceof ParameterizedType) {
-            return parameterizedTypeToString((ParameterizedType) type);
-        }
-        if (type instanceof WildcardType) {
-            return wildcardTypeToString((WildcardType) type);
-        }
-        if (type instanceof TypeVariable<?>) {
-            return typeVariableToString((TypeVariable<?>) type);
-        }
-        if (type instanceof GenericArrayType) {
-            return genericArrayTypeToString((GenericArrayType) type);
+            return replacementType;
         }
-        throw new IllegalArgumentException(ObjectUtils.identityToString(type));
+        return type;
     }
 
     /**
@@ -1725,63 +1683,74 @@ public class TypeUtils {
                 buf.insert(0, c.getSimpleName()).insert(0, '.');
                 c = c.getEnclosingClass();
             }
-        } else if (d instanceof Type) {// not possible as of now
-            buf.append(toString((Type) d));
-        } else {
-            buf.append(d);
-        }
-        return buf.append(':').append(typeVariableToString(var)).toString();
-    }
-
-    /**
-     * Wraps the specified {@link Type} in a {@link Typed} wrapper.
-     *
-     * @param <T> inferred generic type
-     * @param type to wrap
-     * @return Typed&lt;T&gt;
-     * @since 3.2
-     */
-    public static <T> Typed<T> wrap(final Type type) {
-        return () -> type;
+        } else if (d instanceof Type) {// not possible as of now
+            buf.append(toString((Type) d));
+        } else {
+            buf.append(d);
+        }
+        return buf.append(':').append(typeVariableToString(var)).toString();
     }
 
-    /**
-     * Wraps the specified {@link Class} in a {@link Typed} wrapper.
-     *
-     * @param <T> generic type
-     * @param type to wrap
-     * @return Typed&lt;T&gt;
-     * @since 3.2
-     */
-    public static <T> Typed<T> wrap(final Class<T> type) {
-        return wrap((Type) type);
+    private static <T> String toString(final T object) {
+        return object instanceof Type ? toString((Type) object) : object.toString();
     }
 
     /**
-     * Formats a {@link Class} as a {@link String}.
+     * Formats a given type as a Java-esque String.
      *
-     * @param cls {@code Class} to format
+     * @param type the type to create a String representation for, not {@code null}
      * @return String
      * @since 3.2
      */
-    private static String classToString(final Class<?> cls) {
-        if (cls.isArray()) {
-            return toString(cls.getComponentType()) + "[]";
+    public static String toString(final Type type) {
+        Validate.notNull(type);
+        if (type instanceof Class<?>) {
+            return classToString((Class<?>) type);
+        }
+        if (type instanceof ParameterizedType) {
+            return parameterizedTypeToString((ParameterizedType) type);
         }
+        if (type instanceof WildcardType) {
+            return wildcardTypeToString((WildcardType) type);
+        }
+        if (type instanceof TypeVariable<?>) {
+            return typeVariableToString((TypeVariable<?>) type);
+        }
+        if (type instanceof GenericArrayType) {
+            return genericArrayTypeToString((GenericArrayType) type);
+        }
+        throw new IllegalArgumentException(ObjectUtils.identityToString(type));
+    }
 
-        final StringBuilder buf = new StringBuilder();
+    /**
+     * Determines whether or not specified types satisfy the bounds of their
+     * mapped type variables. When a type parameter extends another (such as
+     * {@code <T, S extends T>}), uses another as a type parameter (such as
+     * {@code <T, S extends Comparable>>}), or otherwise depends on
+     * another type variable to be specified, the dependencies must be included
+     * in {@code typeVarAssigns}.
+     *
+     * @param typeVarAssigns specifies the potential types to be assigned to the
+     * type variables, not {@code null}.
+     * @return whether or not the types can be assigned to their respective type
+     * variables.
+     */
+    public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVarAssigns) {
+        Validate.notNull(typeVarAssigns, "typeVarAssigns is null");
+        // all types must be assignable to all the bounds of their mapped
+        // type variable.
+        for (final Map.Entry<TypeVariable<?>, Type> entry : typeVarAssigns.entrySet()) {
+            final TypeVariable<?> typeVar = entry.getKey();
+            final Type type = entry.getValue();
 
-        if (cls.getEnclosingClass() != null) {
-            buf.append(classToString(cls.getEnclosingClass())).append('.').append(cls.getSimpleName());
-        } else {
-            buf.append(cls.getName());
-        }
-        if (cls.getTypeParameters().length > 0) {
-            buf.append('<');
-            appendAllTo(buf, ", ", cls.getTypeParameters());
-            buf.append('>');
+            for (final Type bound : getImplicitBounds(typeVar)) {
+                if (!isAssignable(type, substituteTypeVariables(bound, typeVarAssigns),
+                        typeVarAssigns)) {
+                    return false;
+                }
+            }
         }
-        return buf.toString();
+        return true;
     }
 
     /**
@@ -1802,71 +1771,101 @@ public class TypeUtils {
     }
 
     /**
-     * Formats a {@link ParameterizedType} as a {@link String}.
+     * Unrolls variables in a type bounds array.
      *
-     * @param parameterizedType {@code ParameterizedType} to format
-     * @return String
+     * @param typeArguments assignments {@link Map}
+     * @param bounds in which to expand variables
+     * @return {@code bounds} with any variables reassigned
      * @since 3.2
      */
-    private static String parameterizedTypeToString(final ParameterizedType parameterizedType) {
-        final StringBuilder builder = new StringBuilder();
-
-        final Type useOwner = parameterizedType.getOwnerType();
-        final Class<?> raw = (Class<?>) parameterizedType.getRawType();
-
-        if (useOwner == null) {
-            builder.append(raw.getName());
-        } else {
-            if (useOwner instanceof Class<?>) {
-                builder.append(((Class<?>) useOwner).getName());
+    private static Type[] unrollBounds(final Map<TypeVariable<?>, Type> typeArguments, final Type[] bounds) {
+        Type[] result = bounds;
+        int i = 0;
+        for (; i < result.length; i++) {
+            final Type unrolled = unrollVariables(typeArguments, result[i]);
+            if (unrolled == null) {
+                result = ArrayUtils.remove(result, i--);
             } else {
-                builder.append(useOwner.toString());
+                result[i] = unrolled;
             }
-            builder.append('.').append(raw.getSimpleName());
-        }
-
-        final int[] recursiveTypeIndexes = findRecursiveTypes(parameterizedType);
-
-        if (recursiveTypeIndexes.length > 0) {
-            appendRecursiveTypes(builder, recursiveTypeIndexes, parameterizedType.getActualTypeArguments());
-        } else {
-            appendAllTo(builder.append('<'), ", ", parameterizedType.getActualTypeArguments()).append('>');
         }
-
-        return builder.toString();
+        return result;
     }
 
-    private static void appendRecursiveTypes(final StringBuilder builder, final int[] recursiveTypeIndexes,
-        final Type[] argumentTypes) {
-        for (int i = 0; i < recursiveTypeIndexes.length; i++) {
-            appendAllTo(builder.append('<'), ", ", argumentTypes[i].toString()).append('>');
-        }
-
-        final Type[] argumentsFiltered = ArrayUtils.removeAll(argumentTypes, recursiveTypeIndexes);
-
-        if (argumentsFiltered.length > 0) {
-            appendAllTo(builder.append('<'), ", ", argumentsFiltered).append('>');
-        }
+    /**
+     * Look up {@code var} in {@code typeVarAssigns} <em>transitively</em>,
+     * i.e. keep looking until the value found is <em>not</em> a type variable.
+     *
+     * @param typeVariable the type variable to look up
+     * @param typeVarAssigns the map used for the look up
+     * @return Type or {@code null} if some variable was not in the map
+     * @since 3.2
+     */
+    private static Type unrollVariableAssignments(TypeVariable<?> typeVariable,
+        final Map<TypeVariable<?>, Type> typeVarAssigns) {
+        Type result;
+        do {
+            result = typeVarAssigns.get(typeVariable);
+            if (result instanceof TypeVariable<?> && !result.equals(typeVariable)) {
+                typeVariable = (TypeVariable<?>) result;
+                continue;
+            }
+            break;
+        } while (true);
+        return result;
     }
 
-    private static int[] findRecursiveTypes(final ParameterizedType parameterizedType) {
-        final Type[] filteredArgumentTypes = Arrays.copyOf(parameterizedType.getActualTypeArguments(),
-            parameterizedType.getActualTypeArguments().length);
-        int[] indexesToRemove = {};
-        for (int i = 0; i < filteredArgumentTypes.length; i++) {
-            if (filteredArgumentTypes[i] instanceof TypeVariable<?>) {
-                if (containsVariableTypeSameParametrizedTypeBound(((TypeVariable<?>) filteredArgumentTypes[i]),
-                    parameterizedType)) {
-                    indexesToRemove = ArrayUtils.add(indexesToRemove, i);
+    /**
+     * Gets a type representing {@code type} with variable assignments "unrolled."
+     *
+     * @param typeArguments as from {@link TypeUtils#getTypeArguments(Type, Class)}
+     * @param type the type to unroll variable assignments for
+     * @return Type
+     * @since 3.2
+     */
+    public static Type unrollVariables(Map<TypeVariable<?>, Type> typeArguments, final Type type) {
+        if (typeArguments == null) {
+            typeArguments = Collections.emptyMap();
+        }
+        if (containsTypeVariables(type)) {
+            if (type instanceof TypeVariable<?>) {
+                return unrollVariables(typeArguments, typeArguments.get(type));
+            }
+            if (type instanceof ParameterizedType) {
+                final ParameterizedType p = (ParameterizedType) type;
+                final Map<TypeVariable<?>, Type> parameterizedTypeArguments;
+                if (p.getOwnerType() == null) {
+                    parameterizedTypeArguments = typeArguments;
+                } else {
+                    parameterizedTypeArguments = new HashMap<>(typeArguments);
+                    parameterizedTypeArguments.putAll(getTypeArguments(p));
+                }
+                final Type[] args = p.getActualTypeArguments();
+                for (int i = 0; i < args.length; i++) {
+                    final Type unrolled = unrollVariables(parameterizedTypeArguments, args[i]);
+                    if (unrolled != null) {
+                        args[i] = unrolled;
+                    }
                 }
+                return parameterizeWithOwner(p.getOwnerType(), (Class<?>) p.getRawType(), args);
+            }
+            if (type instanceof WildcardType) {
+                final WildcardType wild = (WildcardType) type;
+                return wildcardType().withUpperBounds(unrollBounds(typeArguments, wild.getUpperBounds()))
+                    .withLowerBounds(unrollBounds(typeArguments, wild.getLowerBounds())).build();
             }
         }
-        return indexesToRemove;
+        return type;
     }
 
-    private static boolean containsVariableTypeSameParametrizedTypeBound(final TypeVariable<?> typeVariable,
-        final ParameterizedType parameterizedType) {
-        return ArrayUtils.contains(typeVariable.getBounds(), parameterizedType);
+    /**
+     * Gets a {@link WildcardTypeBuilder}.
+     *
+     * @return {@link WildcardTypeBuilder}
+     * @since 3.2
+     */
+    public static WildcardTypeBuilder wildcardType() {
+        return new WildcardTypeBuilder();
     }
 
     /**
@@ -1889,39 +1888,40 @@ public class TypeUtils {
     }
 
     /**
-     * Formats a {@link GenericArrayType} as a {@link String}.
+     * Wraps the specified {@link Class} in a {@link Typed} wrapper.
      *
-     * @param genericArrayType {@code GenericArrayType} to format
-     * @return String
+     * @param <T> generic type
+     * @param type to wrap
+     * @return Typed&lt;T&gt;
      * @since 3.2
      */
-    private static String genericArrayTypeToString(final GenericArrayType genericArrayType) {
-        return String.format("%s[]", toString(genericArrayType.getGenericComponentType()));
+    public static <T> Typed<T> wrap(final Class<T> type) {
+        return wrap((Type) type);
     }
 
     /**
-     * Appends {@code types} to {@code builder} with separator {@code sep}.
+     * Wraps the specified {@link Type} in a {@link Typed} wrapper.
      *
-     * @param builder destination
-     * @param sep separator
-     * @param types to append
-     * @return {@code builder}
+     * @param <T> inferred generic type
+     * @param type to wrap
+     * @return Typed&lt;T&gt;
      * @since 3.2
      */
-    private static <T> StringBuilder appendAllTo(final StringBuilder builder, final String sep,
-        @SuppressWarnings("unchecked") final T... types) {
-        Validate.notEmpty(Validate.noNullElements(types));
-        if (types.length > 0) {
-            builder.append(toString(types[0]));
-            for (int i = 1; i < types.length; i++) {
-                builder.append(sep).append(toString(types[i]));
-            }
-        }
-        return builder;
+    public static <T> Typed<T> wrap(final Type type) {
+        return () -> type;
     }
 
-    private static <T> String toString(final T object) {
-        return object instanceof Type ? toString((Type) object) : object.toString();
+    /**
+     * {@code TypeUtils} instances should NOT be constructed in standard
+     * programming. Instead, the class should be used as
+     * {@code TypeUtils.isAssignable(cls, toClass)}.
+     * <p>
+     * This constructor is public to permit tools that require a JavaBean instance
+     * to operate.
+     * </p>
+     */
+    public TypeUtils() {
+        super();
     }
 
 }


[commons-lang] 01/03: Javadoc.

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git

commit 46cdc660f23dac18b236fd34f6694e9d764606a4
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Nov 15 09:37:10 2020 -0500

    Javadoc.
---
 .../apache/commons/lang3/reflect/TypeUtils.java    | 183 ++++++++++++---------
 1 file changed, 106 insertions(+), 77 deletions(-)

diff --git a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
index a20f62b..35ad795 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
@@ -39,8 +39,8 @@ import org.apache.commons.lang3.Validate;
 import org.apache.commons.lang3.builder.Builder;
 
 /**
- * <p> Utility methods focusing on type inspection, particularly with regard to
- * generics. </p>
+ * Utility methods focusing on type inspection, particularly with regard to
+ * generics.
  *
  * @since 3.0
  */
@@ -285,21 +285,23 @@ public class TypeUtils {
     public static final WildcardType WILDCARD_ALL = wildcardType().withUpperBounds(Object.class).build();
 
     /**
-     * <p>{@code TypeUtils} instances should NOT be constructed in standard
+     * {@code TypeUtils} instances should NOT be constructed in standard
      * programming. Instead, the class should be used as
-     * {@code TypeUtils.isAssignable(cls, toClass)}.</p> <p>This
-     * constructor is public to permit tools that require a JavaBean instance to
-     * operate.</p>
+     * {@code TypeUtils.isAssignable(cls, toClass)}.
+     * <p>
+     * This constructor is public to permit tools that require a JavaBean instance
+     * to operate.
+     * </p>
      */
     public TypeUtils() {
         super();
     }
 
     /**
-     * <p>Checks if the subject type may be implicitly cast to the target type
+     * Tests if the subject type may be implicitly cast to the target type
      * following the Java generics rules. If both types are {@link Class}
      * objects, the method returns the result of
-     * {@link ClassUtils#isAssignable(Class, Class)}.</p>
+     * {@link ClassUtils#isAssignable(Class, Class)}.
      *
      * @param type the subject type to be assigned to the target type
      * @param toType the target type
@@ -310,8 +312,8 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Checks if the subject type may be implicitly cast to the target type
-     * following the Java generics rules.</p>
+     * Tests if the subject type may be implicitly cast to the target type
+     * following the Java generics rules.
      *
      * @param type the subject type to be assigned to the target type
      * @param toType the target type
@@ -344,8 +346,8 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Checks if the subject type may be implicitly cast to the target class
-     * following the Java generics rules.</p>
+     * Tests if the subject type may be implicitly cast to the target class
+     * following the Java generics rules.
      *
      * @param type the subject type to be assigned to the target type
      * @param toClass the target class
@@ -410,8 +412,8 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Checks if the subject type may be implicitly cast to the target
-     * parameterized type following the Java generics rules.</p>
+     * Tests if the subject type may be implicitly cast to the target
+     * parameterized type following the Java generics rules.
      *
      * @param type the subject type to be assigned to the target type
      * @param toParameterizedType the target parameterized type
@@ -482,6 +484,7 @@ public class TypeUtils {
     /**
      * Look up {@code var} in {@code typeVarAssigns} <em>transitively</em>,
      * i.e. keep looking until the value found is <em>not</em> a type variable.
+     *
      * @param typeVariable the type variable to look up
      * @param typeVarAssigns the map used for the look up
      * @return Type or {@code null} if some variable was not in the map
@@ -502,8 +505,8 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Checks if the subject type may be implicitly cast to the target
-     * generic array type following the Java generics rules.</p>
+     * Tests if the subject type may be implicitly cast to the target
+     * generic array type following the Java generics rules.
      *
      * @param type the subject type to be assigned to the target type
      * @param toGenericArrayType the target generic array type
@@ -578,8 +581,8 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Checks if the subject type may be implicitly cast to the target
-     * wildcard type following the Java generics rules.</p>
+     * Tests if the subject type may be implicitly cast to the target
+     * wildcard type following the Java generics rules.
      *
      * @param type the subject type to be assigned to the target type
      * @param toWildcardType the target wildcard type
@@ -665,8 +668,8 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Checks if the subject type may be implicitly cast to the target type
-     * variable following the Java generics rules.</p>
+     * Tests if the subject type may be implicitly cast to the target type
+     * variable following the Java generics rules.
      *
      * @param type the subject type to be assigned to the target type
      * @param toTypeVariable the target type variable
@@ -713,7 +716,7 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Find the mapping for {@code type} in {@code typeVarAssigns}.</p>
+     * Finds the mapping for {@code type} in {@code typeVarAssigns}.
      *
      * @param type the type to be replaced
      * @param typeVarAssigns the map with type variables
@@ -734,12 +737,11 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Retrieves all the type arguments for this parameterized type
+     * Gets all the type arguments for this parameterized type
      * including owner hierarchy arguments such as
      * {@code Outer<K, V>.Inner<T>.DeepInner<E>} .
      * The arguments are returned in a
      * {@link Map} specifying the argument type for each {@link TypeVariable}.
-     * </p>
      *
      * @param type specifies the subject parameterized type from which to
      *             harvest the parameters.
@@ -751,15 +753,20 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Gets the type arguments of a class/interface based on a subtype. For
+     * Gets the type arguments of a class/interface based on a subtype. For
      * instance, this method will determine that both of the parameters for the
      * interface {@link Map} are {@link Object} for the subtype
      * {@link java.util.Properties Properties} even though the subtype does not
-     * directly implement the {@code Map} interface.</p>
-     * <p>This method returns {@code null} if {@code type} is not assignable to
+     * directly implement the {@code Map} interface.
+     * 
+     * <p>
+     * This method returns {@code null} if {@code type} is not assignable to
      * {@code toClass}. It returns an empty map if none of the classes or
-     * interfaces in its inheritance hierarchy specify any type arguments.</p>
-     * <p>A side effect of this method is that it also retrieves the type
+     * interfaces in its inheritance hierarchy specify any type arguments.
+     * </p>
+     *
+     * <p>
+     * A side effect of this method is that it also retrieves the type
      * arguments for the classes and interfaces that are part of the hierarchy
      * between {@code type} and {@code toClass}. So with the above
      * example, this method will also determine that the type arguments for
@@ -772,7 +779,8 @@ public class TypeUtils {
      * this method will look at the inheritance hierarchy of only one of the
      * implementations/subclasses; the first interface encountered that isn't a
      * subinterface to one of the others in the {@code type} to
-     * {@code toClass} hierarchy.</p>
+     * {@code toClass} hierarchy.
+     * </p>
      *
      * @param type the type from which to determine the type parameters of
      * {@code toClass}
@@ -787,7 +795,7 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Return a map of the type arguments of {@code type} in the context of {@code toClass}.</p>
+     * Gets a map of the type arguments of {@code type} in the context of {@code toClass}.
      *
      * @param type the type in question
      * @param toClass the class
@@ -836,7 +844,7 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Return a map of the type arguments of a parameterized type in the context of {@code toClass}.</p>
+     * Gets a map of the type arguments of a parameterized type in the context of {@code toClass}.
      *
      * @param parameterizedType the parameterized type
      * @param toClass the class
@@ -891,7 +899,7 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Return a map of the type arguments of a class in the context of {@code toClass}.</p>
+     * Gets a map of the type arguments of a class in the context of {@code toClass}.
      *
      * @param cls the class in question
      * @param toClass the context class
@@ -932,13 +940,16 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Tries to determine the type arguments of a class/interface based on a
+     * Tries to determine the type arguments of a class/interface based on a
      * super parameterized type's type arguments. This method is the inverse of
      * {@link #getTypeArguments(Type, Class)} which gets a class/interface's
      * type arguments based on a subtype. It is far more limited in determining
      * the type arguments for the subject class's type variables in that it can
      * only determine those parameters that map from the subject {@link Class}
-     * object to the supertype.</p> <p>Example: {@link java.util.TreeSet
+     * object to the supertype.
+     * 
+     * <p>
+     * Example: {@link java.util.TreeSet
      * TreeSet} sets its parameter as the parameter for
      * {@link java.util.NavigableSet NavigableSet}, which in turn sets the
      * parameter of {@link java.util.SortedSet}, which in turn sets the
@@ -949,7 +960,8 @@ public class TypeUtils {
      * determine that based on the super type {@code Iterable<? extends
      * Map<Integer, ? extends Collection<?>>>}, the parameter of
      * {@code TreeSet} is {@code ? extends Map<Integer, ? extends
-     * Collection<?>>}.</p>
+     * Collection<?>>}.
+     * </p>
      *
      * @param cls the class whose type parameters are to be determined, not {@code null}
      * @param superType the super type from which {@code cls}'s type
@@ -994,7 +1006,7 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Performs a mapping of type variables.</p>
+     * Maps type variables.
      *
      * @param <T> the generic type of the class in question
      * @param cls the class in question
@@ -1041,8 +1053,8 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Get the closest parent type to the
-     * super class specified by {@code superClass}.</p>
+     * Gets the closest parent type to the
+     * super class specified by {@code superClass}.
      *
      * @param cls the class in question
      * @param superClass the super class
@@ -1089,8 +1101,8 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Checks if the given value can be assigned to the target type
-     * following the Java generics rules.</p>
+     * Tests if the given value can be assigned to the target type
+     * following the Java generics rules.
      *
      * @param value the value to be checked
      * @param type the target type
@@ -1106,10 +1118,13 @@ public class TypeUtils {
     }
 
     /**
-     * <p>This method strips out the redundant upper bound types in type
+     * Strips out the redundant upper bound types in type
      * variable types and wildcard types (or it would with wildcard types if
-     * multiple upper bounds were allowed).</p> <p>Example, with the variable
-     * type declaration:
+     * multiple upper bounds were allowed).
+     * 
+     * <p>
+     * Example, with the variable type declaration:
+     * </p>
      *
      * <pre>&lt;K extends java.util.Collection&lt;String&gt; &amp;
      * java.util.List&lt;String&gt;&gt;</pre>
@@ -1154,10 +1169,10 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Returns an array containing the sole type of {@link Object} if
+     * Gets an array containing the sole type of {@link Object} if
      * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it
      * returns the result of {@link TypeVariable#getBounds()} passed into
-     * {@link #normalizeUpperBounds}.</p>
+     * {@link #normalizeUpperBounds}.
      *
      * @param typeVariable the subject type variable, not {@code null}
      * @return a non-empty array containing the bounds of the type variable.
@@ -1170,10 +1185,10 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Returns an array containing the sole value of {@link Object} if
+     * Gets an array containing the sole value of {@link Object} if
      * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise,
      * it returns the result of {@link WildcardType#getUpperBounds()}
-     * passed into {@link #normalizeUpperBounds}.</p>
+     * passed into {@link #normalizeUpperBounds}.
      *
      * @param wildcardType the subject wildcard type, not {@code null}
      * @return a non-empty array containing the upper bounds of the wildcard
@@ -1187,9 +1202,9 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Returns an array containing a single value of {@code null} if
+     * Gets an array containing a single value of {@code null} if
      * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise,
-     * it returns the result of {@link WildcardType#getLowerBounds()}.</p>
+     * it returns the result of {@link WildcardType#getLowerBounds()}.
      *
      * @param wildcardType the subject wildcard type, not {@code null}
      * @return a non-empty array containing the lower bounds of the wildcard
@@ -1203,12 +1218,12 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Determines whether or not specified types satisfy the bounds of their
+     * Determines whether or not specified types satisfy the bounds of their
      * mapped type variables. When a type parameter extends another (such as
      * {@code <T, S extends T>}), uses another as a type parameter (such as
      * {@code <T, S extends Comparable>>}), or otherwise depends on
      * another type variable to be specified, the dependencies must be included
-     * in {@code typeVarAssigns}.</p>
+     * in {@code typeVarAssigns}.
      *
      * @param typeVarAssigns specifies the potential types to be assigned to the
      * type variables, not {@code null}.
@@ -1234,7 +1249,7 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Transforms the passed in type to a {@link Class} object. Type-checking method of convenience.</p>
+     * Transforms the passed in type to a {@link Class} object. Type-checking method of convenience.
      *
      * @param parameterizedType the type to be converted
      * @return the corresponding {@code Class} object
@@ -1256,11 +1271,11 @@ public class TypeUtils {
     }
 
     /**
-     * <p>Get the raw type of a Java type, given its context. Primarily for use
+     * Gets the raw type of a Java type, given its context. Primarily for use
      * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
      * not know the runtime type of {@code type}: if you know you have a
      * {@link Class} instance, it is already raw; if you know you have a
-     * {@link ParameterizedType}, its raw type is only a method call away.</p>
+     * {@link ParameterizedType}, its raw type is only a method call away.
      *
      * @param type to resolve
      * @param assigningType type to be resolved against
@@ -1332,7 +1347,8 @@ public class TypeUtils {
     }
 
     /**
-     * Learn whether the specified type denotes an array type.
+     * Tests whether the specified type denotes an array type.
+     *
      * @param type the type to be checked
      * @return {@code true} if {@code type} is an array class or a {@link GenericArrayType}.
      */
@@ -1342,6 +1358,7 @@ public class TypeUtils {
 
     /**
      * Gets the array component type of {@code type}.
+     *
      * @param type the type to be checked
      * @return component type or null if type is not an array type
      */
@@ -1400,7 +1417,7 @@ public class TypeUtils {
     }
 
     /**
-     * Local helper method to unroll variables in a type bounds array.
+     * Unrolls variables in a type bounds array.
      *
      * @param typeArguments assignments {@link Map}
      * @param bounds in which to expand variables
@@ -1422,7 +1439,7 @@ public class TypeUtils {
     }
 
     /**
-     * Learn, recursively, whether any of the type parameters associated with {@code type} are bound to variables.
+     * Tests, recursively, whether any of the type parameters associated with {@code type} are bound to variables.
      *
      * @param type the type to check for type variables
      * @return boolean
@@ -1452,7 +1469,7 @@ public class TypeUtils {
     }
 
     /**
-     * Create a parameterized type instance.
+     * Creates a parameterized type instance.
      *
      * @param rawClass the raw class to create a parameterized type instance for
      * @param typeArguments the types used for parameterization
@@ -1464,7 +1481,7 @@ public class TypeUtils {
     }
 
     /**
-     * Create a parameterized type instance.
+     * Creates a parameterized type instance.
      *
      * @param rawClass the raw class to create a parameterized type instance for
      * @param typeArgMappings the mapping used for parameterization
@@ -1480,7 +1497,7 @@ public class TypeUtils {
     }
 
     /**
-     * Create a parameterized type instance.
+     * Creates a parameterized type instance.
      *
      * @param owner the owning type
      * @param rawClass the raw class to create a parameterized type instance for
@@ -1512,7 +1529,7 @@ public class TypeUtils {
     }
 
     /**
-     * Create a parameterized type instance.
+     * Creates a parameterized type instance.
      *
      * @param owner the owning type
      * @param rawClass the raw class to create a parameterized type instance for
@@ -1530,6 +1547,7 @@ public class TypeUtils {
 
     /**
      * Helper method to establish the formal parameters for a parameterized type.
+     *
      * @param mappings map containing the assignments
      * @param variables expected map keys
      * @return array of map values corresponding to specified keys
@@ -1546,6 +1564,7 @@ public class TypeUtils {
 
     /**
      * Gets a {@link WildcardTypeBuilder}.
+     *
      * @return {@link WildcardTypeBuilder}
      * @since 3.2
      */
@@ -1554,7 +1573,7 @@ public class TypeUtils {
     }
 
     /**
-     * Create a generic array type instance.
+     * Creates a generic array type instance.
      *
      * @param componentType the type of the elements of the array. For example the component type of {@code boolean[]}
      *                      is {@code boolean}
@@ -1566,7 +1585,7 @@ public class TypeUtils {
     }
 
     /**
-     * Check equality of types.
+     * Tests equality of types.
      *
      * @param type1 the first type
      * @param type2 the second type
@@ -1590,7 +1609,8 @@ public class TypeUtils {
     }
 
     /**
-     * Learn whether {@code t} equals {@code p}.
+     * Tests whether {@code t} equals {@code p}.
+     *
      * @param parameterizedType LHS
      * @param type RHS
      * @return boolean
@@ -1608,7 +1628,8 @@ public class TypeUtils {
     }
 
     /**
-     * Learn whether {@code t} equals {@code a}.
+     * Tests whether {@code t} equals {@code a}.
+     *
      * @param genericArrayType LHS
      * @param type RHS
      * @return boolean
@@ -1620,7 +1641,8 @@ public class TypeUtils {
     }
 
     /**
-     * Learn whether {@code t} equals {@code w}.
+     * Tests whether {@code t} equals {@code w}.
+     *
      * @param wildcardType LHS
      * @param type RHS
      * @return boolean
@@ -1636,7 +1658,8 @@ public class TypeUtils {
     }
 
     /**
-     * Learn whether {@code t1} equals {@code t2}.
+     * Tests whether {@code t1} equals {@code t2}.
+     *
      * @param type1 LHS
      * @param type2 RHS
      * @return boolean
@@ -1655,7 +1678,7 @@ public class TypeUtils {
     }
 
     /**
-     * Present a given type as a Java-esque String.
+     * Formats a given type as a Java-esque String.
      *
      * @param type the type to create a String representation for, not {@code null}
      * @return String
@@ -1682,7 +1705,7 @@ public class TypeUtils {
     }
 
     /**
-     * Format a {@link TypeVariable} including its {@link GenericDeclaration}.
+     * Formats a {@link TypeVariable} including its {@link GenericDeclaration}.
      *
      * @param var the type variable to create a String representation for, not {@code null}
      * @return String
@@ -1711,7 +1734,7 @@ public class TypeUtils {
     }
 
     /**
-     * Wrap the specified {@link Type} in a {@link Typed} wrapper.
+     * Wraps the specified {@link Type} in a {@link Typed} wrapper.
      *
      * @param <T> inferred generic type
      * @param type to wrap
@@ -1723,7 +1746,7 @@ public class TypeUtils {
     }
 
     /**
-     * Wrap the specified {@link Class} in a {@link Typed} wrapper.
+     * Wraps the specified {@link Class} in a {@link Typed} wrapper.
      *
      * @param <T> generic type
      * @param type to wrap
@@ -1735,7 +1758,8 @@ public class TypeUtils {
     }
 
     /**
-     * Format a {@link Class} as a {@link String}.
+     * Formats a {@link Class} as a {@link String}.
+     *
      * @param cls {@code Class} to format
      * @return String
      * @since 3.2
@@ -1761,7 +1785,8 @@ public class TypeUtils {
     }
 
     /**
-     * Format a {@link TypeVariable} as a {@link String}.
+     * Formats a {@link TypeVariable} as a {@link String}.
+     *
      * @param typeVariable {@code TypeVariable} to format
      * @return String
      * @since 3.2
@@ -1777,7 +1802,8 @@ public class TypeUtils {
     }
 
     /**
-     * Format a {@link ParameterizedType} as a {@link String}.
+     * Formats a {@link ParameterizedType} as a {@link String}.
+     *
      * @param parameterizedType {@code ParameterizedType} to format
      * @return String
      * @since 3.2
@@ -1844,7 +1870,8 @@ public class TypeUtils {
     }
 
     /**
-     * Format a {@link WildcardType} as a {@link String}.
+     * Formats a {@link WildcardType} as a {@link String}.
+     *
      * @param wildcardType {@code WildcardType} to format
      * @return String
      * @since 3.2
@@ -1862,7 +1889,8 @@ public class TypeUtils {
     }
 
     /**
-     * Format a {@link GenericArrayType} as a {@link String}.
+     * Formats a {@link GenericArrayType} as a {@link String}.
+     *
      * @param genericArrayType {@code GenericArrayType} to format
      * @return String
      * @since 3.2
@@ -1872,7 +1900,8 @@ public class TypeUtils {
     }
 
     /**
-     * Append {@code types} to {@code builder} with separator {@code sep}.
+     * Appends {@code types} to {@code builder} with separator {@code sep}.
+     *
      * @param builder destination
      * @param sep separator
      * @param types to append


[commons-lang] 03/03: Consistently use just the parameter name for the message of NullPointerExceptions.

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git

commit 43b2326713ab952833c2ed4c88fbb0b34cb65436
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Nov 15 10:40:31 2020 -0500

    Consistently use just the parameter name for the message of
    NullPointerExceptions.
---
 .../java/org/apache/commons/lang3/CharRange.java   |  2 +-
 .../java/org/apache/commons/lang3/CharUtils.java   |  4 +-
 .../org/apache/commons/lang3/ClassPathUtils.java   | 16 ++---
 .../java/org/apache/commons/lang3/ClassUtils.java  |  2 +-
 .../java/org/apache/commons/lang3/ObjectUtils.java | 10 ++--
 src/main/java/org/apache/commons/lang3/Range.java  |  2 +-
 .../apache/commons/lang3/SerializationUtils.java   |  2 +-
 .../java/org/apache/commons/lang3/ThreadUtils.java | 14 ++---
 .../apache/commons/lang3/builder/DiffBuilder.java  |  8 +--
 .../apache/commons/lang3/builder/DiffResult.java   | 24 ++++----
 .../commons/lang3/builder/HashCodeBuilder.java     |  2 +-
 .../lang3/builder/ReflectionToStringBuilder.java   |  2 +-
 .../commons/lang3/builder/ToStringBuilder.java     |  2 +-
 .../lang3/concurrent/BasicThreadFactory.java       |  6 +-
 .../concurrent/CallableBackgroundInitializer.java  |  6 +-
 .../concurrent/MultiBackgroundInitializer.java     | 13 ++--
 .../commons/lang3/event/EventListenerSupport.java  |  8 +--
 .../org/apache/commons/lang3/math/Fraction.java    |  8 +--
 .../apache/commons/lang3/math/IEEE754rUtils.java   |  8 +--
 .../org/apache/commons/lang3/math/NumberUtils.java |  2 +-
 .../commons/lang3/reflect/ConstructorUtils.java    |  6 +-
 .../apache/commons/lang3/reflect/FieldUtils.java   | 26 ++++----
 .../apache/commons/lang3/reflect/MethodUtils.java  | 12 ++--
 .../apache/commons/lang3/reflect/TypeUtils.java    | 70 +++++++++++-----------
 .../org/apache/commons/lang3/time/DateUtils.java   |  2 +-
 .../org/apache/commons/lang3/time/FormatCache.java |  2 +-
 .../org/apache/commons/lang3/CharRangeTest.java    |  2 +-
 27 files changed, 130 insertions(+), 131 deletions(-)

diff --git a/src/main/java/org/apache/commons/lang3/CharRange.java b/src/main/java/org/apache/commons/lang3/CharRange.java
index 90977fb..62ee82b 100644
--- a/src/main/java/org/apache/commons/lang3/CharRange.java
+++ b/src/main/java/org/apache/commons/lang3/CharRange.java
@@ -187,7 +187,7 @@ final class CharRange implements Iterable<Character>, Serializable {
      * @throws IllegalArgumentException if {@code null} input
      */
     public boolean contains(final CharRange range) {
-        Validate.notNull(range, "The Range must not be null");
+        Validate.notNull(range, "range");
         if (negated) {
             if (range.negated) {
                 return start >= range.start && end <= range.end;
diff --git a/src/main/java/org/apache/commons/lang3/CharUtils.java b/src/main/java/org/apache/commons/lang3/CharUtils.java
index 4e07693..1119197 100644
--- a/src/main/java/org/apache/commons/lang3/CharUtils.java
+++ b/src/main/java/org/apache/commons/lang3/CharUtils.java
@@ -134,7 +134,7 @@ public class CharUtils {
      * @throws NullPointerException if the Character is null
      */
     public static char toChar(final Character ch) {
-        Validate.notNull(ch, "The Character must not be null");
+        Validate.notNull(ch, "ch");
         return ch.charValue();
     }
 
@@ -265,7 +265,7 @@ public class CharUtils {
      * @throws IllegalArgumentException if the Character is not ASCII numeric
      */
     public static int toIntValue(final Character ch) {
-        Validate.notNull(ch, "The character must not be null");
+        Validate.notNull(ch, "ch");
         return toIntValue(ch.charValue());
     }
 
diff --git a/src/main/java/org/apache/commons/lang3/ClassPathUtils.java b/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
index df3773a..6b3a142 100644
--- a/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
@@ -55,8 +55,8 @@ public class ClassPathUtils {
      * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
      */
     public static String toFullyQualifiedName(final Class<?> context, final String resourceName) {
-        Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
-        Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
+        Validate.notNull(context, "context" );
+        Validate.notNull(resourceName, "resourceName");
         return toFullyQualifiedName(context.getPackage(), resourceName);
     }
 
@@ -77,8 +77,8 @@ public class ClassPathUtils {
      * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
      */
     public static String toFullyQualifiedName(final Package context, final String resourceName) {
-        Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
-        Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
+        Validate.notNull(context, "context" );
+        Validate.notNull(resourceName, "resourceName");
         return context.getName() + "." + resourceName;
     }
 
@@ -99,8 +99,8 @@ public class ClassPathUtils {
      * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
      */
     public static String toFullyQualifiedPath(final Class<?> context, final String resourceName) {
-        Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
-        Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
+        Validate.notNull(context, "context" );
+        Validate.notNull(resourceName, "resourceName");
         return toFullyQualifiedPath(context.getPackage(), resourceName);
     }
 
@@ -122,8 +122,8 @@ public class ClassPathUtils {
      * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
      */
     public static String toFullyQualifiedPath(final Package context, final String resourceName) {
-        Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
-        Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
+        Validate.notNull(context, "context" );
+        Validate.notNull(resourceName, "resourceName");
         return context.getName().replace('.', '/') + "/" + resourceName;
     }
 
diff --git a/src/main/java/org/apache/commons/lang3/ClassUtils.java b/src/main/java/org/apache/commons/lang3/ClassUtils.java
index a6d1d1d..9cd9ede 100644
--- a/src/main/java/org/apache/commons/lang3/ClassUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ClassUtils.java
@@ -1199,7 +1199,7 @@ public class ClassUtils {
      */
     private static String toCanonicalName(String className) {
         className = StringUtils.deleteWhitespace(className);
-        Validate.notNull(className, "className must not be null.");
+        Validate.notNull(className, "className");
         if (className.endsWith("[]")) {
             final StringBuilder classNameBuffer = new StringBuilder();
             while (className.endsWith("[]")) {
diff --git a/src/main/java/org/apache/commons/lang3/ObjectUtils.java b/src/main/java/org/apache/commons/lang3/ObjectUtils.java
index d68021f..b454e99 100644
--- a/src/main/java/org/apache/commons/lang3/ObjectUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ObjectUtils.java
@@ -808,7 +808,7 @@ public class ObjectUtils {
      * @since 3.2
      */
     public static void identityToString(final Appendable appendable, final Object object) throws IOException {
-        Validate.notNull(object, "Cannot get the toString of a null object");
+        Validate.notNull(object, "object");
         appendable.append(object.getClass().getName())
               .append(AT_SIGN)
               .append(Integer.toHexString(System.identityHashCode(object)));
@@ -866,7 +866,7 @@ public class ObjectUtils {
      */
     @Deprecated
     public static void identityToString(final StrBuilder builder, final Object object) {
-        Validate.notNull(object, "Cannot get the toString of a null object");
+        Validate.notNull(object, "object");
         final String name = object.getClass().getName();
         final String hexString = Integer.toHexString(System.identityHashCode(object));
         builder.ensureCapacity(builder.length() +  name.length() + 1 + hexString.length());
@@ -891,7 +891,7 @@ public class ObjectUtils {
      * @since 2.4
      */
     public static void identityToString(final StringBuffer buffer, final Object object) {
-        Validate.notNull(object, "Cannot get the toString of a null object");
+        Validate.notNull(object, "object");
         final String name = object.getClass().getName();
         final String hexString = Integer.toHexString(System.identityHashCode(object));
         buffer.ensureCapacity(buffer.length() + name.length() + 1 + hexString.length());
@@ -916,7 +916,7 @@ public class ObjectUtils {
      * @since 3.2
      */
     public static void identityToString(final StringBuilder builder, final Object object) {
-        Validate.notNull(object, "Cannot get the toString of a null object");
+        Validate.notNull(object, "object");
         final String name = object.getClass().getName();
         final String hexString = Integer.toHexString(System.identityHashCode(object));
         builder.ensureCapacity(builder.length() +  name.length() + 1 + hexString.length());
@@ -1063,7 +1063,7 @@ public class ObjectUtils {
     public static <T> T median(final Comparator<T> comparator, final T... items) {
         Validate.notEmpty(items, "null/empty items");
         Validate.noNullElements(items);
-        Validate.notNull(comparator, "null comparator");
+        Validate.notNull(comparator, "comparator");
         final TreeSet<T> sort = new TreeSet<>(comparator);
         Collections.addAll(sort, items);
         @SuppressWarnings("unchecked") //we know all items added were T instances
diff --git a/src/main/java/org/apache/commons/lang3/Range.java b/src/main/java/org/apache/commons/lang3/Range.java
index 2c9e4b7..5f8889f 100644
--- a/src/main/java/org/apache/commons/lang3/Range.java
+++ b/src/main/java/org/apache/commons/lang3/Range.java
@@ -223,7 +223,7 @@ public final class Range<T> implements Serializable {
      */
     public int elementCompareTo(final T element) {
         // Comparable API says throw NPE on null
-        Validate.notNull(element, "Element is null");
+        Validate.notNull(element, "element");
         if (isAfter(element)) {
             return -1;
         } else if (isBefore(element)) {
diff --git a/src/main/java/org/apache/commons/lang3/SerializationUtils.java b/src/main/java/org/apache/commons/lang3/SerializationUtils.java
index a8269ab..455845a 100644
--- a/src/main/java/org/apache/commons/lang3/SerializationUtils.java
+++ b/src/main/java/org/apache/commons/lang3/SerializationUtils.java
@@ -175,7 +175,7 @@ public class SerializationUtils {
      * @throws SerializationException (runtime) if the serialization fails
      */
     public static <T> T deserialize(final byte[] objectData) {
-        Validate.notNull(objectData, "The byte[] must not be null");
+        Validate.notNull(objectData, "objectData");
         return deserialize(new ByteArrayInputStream(objectData));
     }
 
diff --git a/src/main/java/org/apache/commons/lang3/ThreadUtils.java b/src/main/java/org/apache/commons/lang3/ThreadUtils.java
index fef3dc8..7d52695 100644
--- a/src/main/java/org/apache/commons/lang3/ThreadUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ThreadUtils.java
@@ -50,7 +50,7 @@ public class ThreadUtils {
      *          thread groups from this thread's thread group up to the system thread group
      */
     public static Thread findThreadById(final long threadId, final ThreadGroup threadGroup) {
-        Validate.notNull(threadGroup, "The thread group must not be null");
+        Validate.notNull(threadGroup, "threadGroup");
         final Thread thread = findThreadById(threadId);
         if (thread != null && threadGroup.equals(thread.getThreadGroup())) {
             return thread;
@@ -73,7 +73,7 @@ public class ThreadUtils {
      *          thread groups from this thread's thread group up to the system thread group
      */
     public static Thread findThreadById(final long threadId, final String threadGroupName) {
-        Validate.notNull(threadGroupName, "The thread group name must not be null");
+        Validate.notNull(threadGroupName, "threadGroupName");
         final Thread thread = findThreadById(threadId);
         if (thread != null && thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals(threadGroupName)) {
             return thread;
@@ -114,8 +114,8 @@ public class ThreadUtils {
      *          thread groups from this thread's thread group up to the system thread group
      */
     public static Collection<Thread> findThreadsByName(final String threadName, final String threadGroupName) {
-        Validate.notNull(threadName, "The thread name must not be null");
-        Validate.notNull(threadGroupName, "The thread group name must not be null");
+        Validate.notNull(threadName, "threadName");
+        Validate.notNull(threadGroupName, "threadGroupName");
 
         final Collection<ThreadGroup> threadGroups = findThreadGroups(new NamePredicate(threadGroupName));
 
@@ -305,7 +305,7 @@ public class ThreadUtils {
          */
         public NamePredicate(final String name) {
             super();
-            Validate.notNull(name, "The name must not be null");
+            Validate.notNull(name, "name");
             this.name = name;
         }
 
@@ -422,8 +422,8 @@ public class ThreadUtils {
      *          thread groups from this thread's thread group up to the system thread group
      */
     public static Collection<ThreadGroup> findThreadGroups(final ThreadGroup group, final boolean recurse, final ThreadGroupPredicate predicate) {
-        Validate.notNull(group, "The group must not be null");
-        Validate.notNull(predicate, "The predicate must not be null");
+        Validate.notNull(group, "group");
+        Validate.notNull(predicate, "predicate");
 
         int count = group.activeGroupCount();
         ThreadGroup[] threadGroups;
diff --git a/src/main/java/org/apache/commons/lang3/builder/DiffBuilder.java b/src/main/java/org/apache/commons/lang3/builder/DiffBuilder.java
index fed655d..f7d5fc8 100644
--- a/src/main/java/org/apache/commons/lang3/builder/DiffBuilder.java
+++ b/src/main/java/org/apache/commons/lang3/builder/DiffBuilder.java
@@ -104,8 +104,8 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
     public DiffBuilder(final T lhs, final T rhs,
             final ToStringStyle style, final boolean testTriviallyEqual) {
 
-        Validate.notNull(lhs, "lhs cannot be null");
-        Validate.notNull(rhs, "rhs cannot be null");
+        Validate.notNull(lhs, "lhs");
+        Validate.notNull(rhs, "rhs");
 
         this.diffs = new ArrayList<>();
         this.left = lhs;
@@ -949,7 +949,7 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
     public DiffBuilder<T> append(final String fieldName,
             final DiffResult<T> diffResult) {
         validateFieldNameNotNull(fieldName);
-        Validate.notNull(diffResult, "Diff result cannot be null");
+        Validate.notNull(diffResult, "diffResult");
         if (objectsTriviallyEqual) {
             return this;
         }
@@ -977,7 +977,7 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
     }
 
     private void validateFieldNameNotNull(final String fieldName) {
-        Validate.notNull(fieldName, "Field name cannot be null");
+        Validate.notNull(fieldName, "fieldName");
     }
 
 }
diff --git a/src/main/java/org/apache/commons/lang3/builder/DiffResult.java b/src/main/java/org/apache/commons/lang3/builder/DiffResult.java
index c55aafc..0a2361d 100644
--- a/src/main/java/org/apache/commons/lang3/builder/DiffResult.java
+++ b/src/main/java/org/apache/commons/lang3/builder/DiffResult.java
@@ -48,7 +48,7 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
 
     private static final String DIFFERS_STRING = "differs from";
 
-    private final List<Diff<?>> diffs;
+    private final List<Diff<?>> diffList;
     private final T lhs;
     private final T rhs;
     private final ToStringStyle style;
@@ -63,7 +63,7 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
      *            the left hand object
      * @param rhs
      *            the right hand object
-     * @param diffs
+     * @param diffList
      *            the list of differences, may be empty
      * @param style
      *            the style to use for the {@link #toString()} method. May be
@@ -71,13 +71,13 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
      *            {@link ToStringStyle#DEFAULT_STYLE} is used
      * @throws NullPointerException if {@code lhs}, {@code rhs} or {@code diffs} is {@code null}
      */
-    DiffResult(final T lhs, final T rhs, final List<Diff<?>> diffs,
+    DiffResult(final T lhs, final T rhs, final List<Diff<?>> diffList,
             final ToStringStyle style) {
-        Validate.notNull(lhs, "Left hand object cannot be null");
-        Validate.notNull(rhs, "Right hand object cannot be null");
-        Validate.notNull(diffs, "List of differences cannot be null");
+        Validate.notNull(lhs, "lhs");
+        Validate.notNull(rhs, "rhs");
+        Validate.notNull(diffList, "diffList");
 
-        this.diffs = diffs;
+        this.diffList = diffList;
         this.lhs = lhs;
         this.rhs = rhs;
 
@@ -117,7 +117,7 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
      * @return an unmodifiable list of {@code Diff}s
      */
     public List<Diff<?>> getDiffs() {
-        return Collections.unmodifiableList(diffs);
+        return Collections.unmodifiableList(diffList);
     }
 
     /**
@@ -128,7 +128,7 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
      * @return the number of differences
      */
     public int getNumberOfDiffs() {
-        return diffs.size();
+        return diffList.size();
     }
 
     /**
@@ -190,14 +190,14 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
      * @return a {@code String} description of the differences.
      */
     public String toString(final ToStringStyle style) {
-        if (diffs.isEmpty()) {
+        if (diffList.isEmpty()) {
             return OBJECTS_SAME_STRING;
         }
 
         final ToStringBuilder lhsBuilder = new ToStringBuilder(lhs, style);
         final ToStringBuilder rhsBuilder = new ToStringBuilder(rhs, style);
 
-        for (final Diff<?> diff : diffs) {
+        for (final Diff<?> diff : diffList) {
             lhsBuilder.append(diff.getFieldName(), diff.getLeft());
             rhsBuilder.append(diff.getFieldName(), diff.getRight());
         }
@@ -215,6 +215,6 @@ public class DiffResult<T> implements Iterable<Diff<?>> {
      */
     @Override
     public Iterator<Diff<?>> iterator() {
-        return diffs.iterator();
+        return diffList.iterator();
     }
 }
diff --git a/src/main/java/org/apache/commons/lang3/builder/HashCodeBuilder.java b/src/main/java/org/apache/commons/lang3/builder/HashCodeBuilder.java
index 7b7bbb0..0a95a74 100644
--- a/src/main/java/org/apache/commons/lang3/builder/HashCodeBuilder.java
+++ b/src/main/java/org/apache/commons/lang3/builder/HashCodeBuilder.java
@@ -358,7 +358,7 @@ public class HashCodeBuilder implements Builder<Integer> {
      */
     public static <T> int reflectionHashCode(final int initialNonZeroOddNumber, final int multiplierNonZeroOddNumber, final T object,
             final boolean testTransients, final Class<? super T> reflectUpToClass, final String... excludeFields) {
-        Validate.notNull(object, "The object to build a hash code for must not be null");
+        Validate.notNull(object, "object");
         final HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber);
         Class<?> clazz = object.getClass();
         reflectionAppend(object, clazz, builder, testTransients, excludeFields);
diff --git a/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java b/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java
index d19aa13..66eb15c 100644
--- a/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java
+++ b/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java
@@ -434,7 +434,7 @@ public class ReflectionToStringBuilder extends ToStringBuilder {
     }
 
     private static Object checkNotNull(final Object obj) {
-        return Validate.notNull(obj, "The Object passed in should not be null.");
+        return Validate.notNull(obj, "obj");
     }
 
     /**
diff --git a/src/main/java/org/apache/commons/lang3/builder/ToStringBuilder.java b/src/main/java/org/apache/commons/lang3/builder/ToStringBuilder.java
index 3522ec3..631c6e4 100644
--- a/src/main/java/org/apache/commons/lang3/builder/ToStringBuilder.java
+++ b/src/main/java/org/apache/commons/lang3/builder/ToStringBuilder.java
@@ -133,7 +133,7 @@ public class ToStringBuilder implements Builder<String> {
      * @throws IllegalArgumentException if the style is {@code null}
      */
     public static void setDefaultStyle(final ToStringStyle style) {
-        defaultStyle = Validate.notNull(style, "The style must not be null");
+        defaultStyle = Validate.notNull(style, "style");
     }
 
     //----------------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/lang3/concurrent/BasicThreadFactory.java b/src/main/java/org/apache/commons/lang3/concurrent/BasicThreadFactory.java
index cd50ad1..631f2e4 100644
--- a/src/main/java/org/apache/commons/lang3/concurrent/BasicThreadFactory.java
+++ b/src/main/java/org/apache/commons/lang3/concurrent/BasicThreadFactory.java
@@ -280,7 +280,7 @@ public class BasicThreadFactory implements ThreadFactory {
          * is <b>null</b>
          */
         public Builder wrappedFactory(final ThreadFactory factory) {
-            Validate.notNull(factory, "Wrapped ThreadFactory must not be null!");
+            Validate.notNull(factory, "factory");
 
             wrappedFactory = factory;
             return this;
@@ -295,7 +295,7 @@ public class BasicThreadFactory implements ThreadFactory {
          * @throws NullPointerException if the naming pattern is <b>null</b>
          */
         public Builder namingPattern(final String pattern) {
-            Validate.notNull(pattern, "Naming pattern must not be null!");
+            Validate.notNull(pattern, "pattern");
 
             namingPattern = pattern;
             return this;
@@ -337,7 +337,7 @@ public class BasicThreadFactory implements ThreadFactory {
          */
         public Builder uncaughtExceptionHandler(
                 final Thread.UncaughtExceptionHandler handler) {
-            Validate.notNull(handler, "Uncaught exception handler must not be null!");
+            Validate.notNull(handler, "handler");
 
             exceptionHandler = handler;
             return this;
diff --git a/src/main/java/org/apache/commons/lang3/concurrent/CallableBackgroundInitializer.java b/src/main/java/org/apache/commons/lang3/concurrent/CallableBackgroundInitializer.java
index 6fca65c..26d7d58 100644
--- a/src/main/java/org/apache/commons/lang3/concurrent/CallableBackgroundInitializer.java
+++ b/src/main/java/org/apache/commons/lang3/concurrent/CallableBackgroundInitializer.java
@@ -116,10 +116,10 @@ public class CallableBackgroundInitializer<T> extends BackgroundInitializer<T> {
      * Tests the passed in {@code Callable} and throws an exception if it is
      * undefined.
      *
-     * @param call the object to check
+     * @param callable the object to check
      * @throws IllegalArgumentException if the {@code Callable} is <b>null</b>
      */
-    private void checkCallable(final Callable<T> call) {
-        Validate.notNull(call, "Callable must not be null!");
+    private void checkCallable(final Callable<T> callable) {
+        Validate.notNull(callable, "callable");
     }
 }
diff --git a/src/main/java/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java b/src/main/java/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java
index 7e36fd9..29b36de 100644
--- a/src/main/java/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java
+++ b/src/main/java/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java
@@ -127,21 +127,20 @@ public class MultiBackgroundInitializer
      * been invoked.
      *
      * @param name the name of the initializer (must not be <b>null</b>)
-     * @param init the {@code BackgroundInitializer} to add (must not be
+     * @param backgroundInitializer the {@code BackgroundInitializer} to add (must not be
      * <b>null</b>)
      * @throws IllegalArgumentException if a required parameter is missing
      * @throws IllegalStateException if {@code start()} has already been called
      */
-    public void addInitializer(final String name, final BackgroundInitializer<?> init) {
-        Validate.notNull(name, "Name of child initializer must not be null!");
-        Validate.notNull(init, "Child initializer must not be null!");
+    public void addInitializer(final String name, final BackgroundInitializer<?> backgroundInitializer) {
+        Validate.notNull(name, "name");
+        Validate.notNull(backgroundInitializer, "backgroundInitializer");
 
         synchronized (this) {
             if (isStarted()) {
-                throw new IllegalStateException(
-                        "addInitializer() must not be called after start()!");
+                throw new IllegalStateException("addInitializer() must not be called after start()!");
             }
-            childInitializers.put(name, init);
+            childInitializers.put(name, backgroundInitializer);
         }
     }
 
diff --git a/src/main/java/org/apache/commons/lang3/event/EventListenerSupport.java b/src/main/java/org/apache/commons/lang3/event/EventListenerSupport.java
index bd79519..315a612 100644
--- a/src/main/java/org/apache/commons/lang3/event/EventListenerSupport.java
+++ b/src/main/java/org/apache/commons/lang3/event/EventListenerSupport.java
@@ -140,8 +140,8 @@ public class EventListenerSupport<L> implements Serializable {
      */
     public EventListenerSupport(final Class<L> listenerInterface, final ClassLoader classLoader) {
         this();
-        Validate.notNull(listenerInterface, "Listener interface cannot be null.");
-        Validate.notNull(classLoader, "ClassLoader cannot be null.");
+        Validate.notNull(listenerInterface, "listenerInterface");
+        Validate.notNull(classLoader, "classLoader");
         Validate.isTrue(listenerInterface.isInterface(), "Class %s is not an interface",
                 listenerInterface.getName());
         initializeTransientFields(listenerInterface, classLoader);
@@ -194,7 +194,7 @@ public class EventListenerSupport<L> implements Serializable {
      * @since 3.5
      */
     public void addListener(final L listener, final boolean allowDuplicate) {
-        Validate.notNull(listener, "Listener object cannot be null.");
+        Validate.notNull(listener, "listener");
         if (allowDuplicate || !listeners.contains(listener)) {
             listeners.add(listener);
         }
@@ -218,7 +218,7 @@ public class EventListenerSupport<L> implements Serializable {
      *         {@code null}.
      */
     public void removeListener(final L listener) {
-        Validate.notNull(listener, "Listener object cannot be null.");
+        Validate.notNull(listener, "listener");
         listeners.remove(listener);
     }
 
diff --git a/src/main/java/org/apache/commons/lang3/math/Fraction.java b/src/main/java/org/apache/commons/lang3/math/Fraction.java
index e90e340..cb5e1f9 100644
--- a/src/main/java/org/apache/commons/lang3/math/Fraction.java
+++ b/src/main/java/org/apache/commons/lang3/math/Fraction.java
@@ -312,7 +312,7 @@ public final class Fraction extends Number implements Comparable<Fraction> {
      * @throws NumberFormatException if the number format is invalid
      */
     public static Fraction getFraction(String str) {
-        Validate.notNull(str, "The string must not be null");
+        Validate.notNull(str, "str");
         // parse double format
         int pos = str.indexOf('.');
         if (pos >= 0) {
@@ -730,7 +730,7 @@ public final class Fraction extends Number implements Comparable<Fraction> {
      *   cannot be represented in an {@code int}.
      */
     private Fraction addSub(final Fraction fraction, final boolean isAdd) {
-        Validate.notNull(fraction, "The fraction must not be null");
+        Validate.notNull(fraction, "fraction");
         // zero is identity for addition.
         if (numerator == 0) {
             return isAdd ? fraction : fraction.negate();
@@ -778,7 +778,7 @@ public final class Fraction extends Number implements Comparable<Fraction> {
      *  {@code Integer.MAX_VALUE}
      */
     public Fraction multiplyBy(final Fraction fraction) {
-        Validate.notNull(fraction, "The fraction must not be null");
+        Validate.notNull(fraction, "fraction");
         if (numerator == 0 || fraction.numerator == 0) {
             return ZERO;
         }
@@ -801,7 +801,7 @@ public final class Fraction extends Number implements Comparable<Fraction> {
      *  {@code Integer.MAX_VALUE}
      */
     public Fraction divideBy(final Fraction fraction) {
-        Validate.notNull(fraction, "The fraction must not be null");
+        Validate.notNull(fraction, "fraction");
         if (fraction.numerator == 0) {
             throw new ArithmeticException("The fraction to divide by must not be zero");
         }
diff --git a/src/main/java/org/apache/commons/lang3/math/IEEE754rUtils.java b/src/main/java/org/apache/commons/lang3/math/IEEE754rUtils.java
index 1af353d..42d3356 100644
--- a/src/main/java/org/apache/commons/lang3/math/IEEE754rUtils.java
+++ b/src/main/java/org/apache/commons/lang3/math/IEEE754rUtils.java
@@ -37,7 +37,7 @@ public class IEEE754rUtils {
       * @since 3.4 Changed signature from min(double[]) to min(double...)
      */
     public static double min(final double... array) {
-        Validate.notNull(array, "The Array must not be null");
+        Validate.notNull(array, "array");
         Validate.isTrue(array.length != 0, "Array cannot be empty.");
 
         // Finds and returns min
@@ -59,7 +59,7 @@ public class IEEE754rUtils {
      * @since 3.4 Changed signature from min(float[]) to min(float...)
      */
     public static float min(final float... array) {
-        Validate.notNull(array, "The Array must not be null");
+        Validate.notNull(array, "array");
         Validate.isTrue(array.length != 0, "Array cannot be empty.");
 
         // Finds and returns min
@@ -149,7 +149,7 @@ public class IEEE754rUtils {
      * @since 3.4 Changed signature from max(double[]) to max(double...)
      */
     public static double max(final double... array) {
-        Validate.notNull(array, "The Array must not be null");
+        Validate.notNull(array, "array");
         Validate.isTrue(array.length != 0, "Array cannot be empty.");
 
         // Finds and returns max
@@ -171,7 +171,7 @@ public class IEEE754rUtils {
      * @since 3.4 Changed signature from max(float[]) to max(float...)
      */
     public static float max(final float... array) {
-        Validate.notNull(array, "The Array must not be null");
+        Validate.notNull(array, "array");
         Validate.isTrue(array.length != 0, "Array cannot be empty.");
 
         // Finds and returns max
diff --git a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
index 05e77d1..1433e4a 100644
--- a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
+++ b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
@@ -1306,7 +1306,7 @@ public class NumberUtils {
      * @throws IllegalArgumentException if {@code array} is either {@code null} or empty
      */
     private static void validateArray(final Object array) {
-        Validate.notNull(array, "The Array must not be null");
+        Validate.notNull(array, "array");
         Validate.isTrue(Array.getLength(array) != 0, "Array cannot be empty.");
     }
 
diff --git a/src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java b/src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java
index 72e6be6..bb0b226 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java
@@ -199,7 +199,7 @@ public class ConstructorUtils {
      */
     public static <T> Constructor<T> getAccessibleConstructor(final Class<T> cls,
             final Class<?>... parameterTypes) {
-        Validate.notNull(cls, "class cannot be null");
+        Validate.notNull(cls, "cls");
         try {
             return getAccessibleConstructor(cls.getConstructor(parameterTypes));
         } catch (final NoSuchMethodException e) {
@@ -219,7 +219,7 @@ public class ConstructorUtils {
      * @throws NullPointerException if {@code ctor} is {@code null}
      */
     public static <T> Constructor<T> getAccessibleConstructor(final Constructor<T> ctor) {
-        Validate.notNull(ctor, "constructor cannot be null");
+        Validate.notNull(ctor, "ctor");
         return MemberUtils.isAccessible(ctor)
                 && isAccessible(ctor.getDeclaringClass()) ? ctor : null;
     }
@@ -244,7 +244,7 @@ public class ConstructorUtils {
      */
     public static <T> Constructor<T> getMatchingAccessibleConstructor(final Class<T> cls,
             final Class<?>... parameterTypes) {
-        Validate.notNull(cls, "class cannot be null");
+        Validate.notNull(cls, "cls");
         // see if we can find the constructor directly
         // most of the time this works and it's much faster
         try {
diff --git a/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java b/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java
index 0e1ed7a..bbf24d1 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java
@@ -86,7 +86,7 @@ public class FieldUtils {
      * in the inheritance hierarchy
      */
     public static Field getField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
-        Validate.notNull(cls, "The class must not be null");
+        Validate.notNull(cls, "cls");
         Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
         // FIXME is this workaround still needed? lang requires Java 6
         // Sun Java 1.3 has a bugged implementation of getField hence we write the
@@ -169,7 +169,7 @@ public class FieldUtils {
      *             if the class is {@code null}, or the field name is blank or empty
      */
     public static Field getDeclaredField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
-        Validate.notNull(cls, "The class must not be null");
+        Validate.notNull(cls, "cls");
         Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
         try {
             // only consider the specified class by using getDeclaredField()
@@ -214,7 +214,7 @@ public class FieldUtils {
      * @since 3.2
      */
     public static List<Field> getAllFieldsList(final Class<?> cls) {
-        Validate.notNull(cls, "The class must not be null");
+        Validate.notNull(cls, "cls");
         final List<Field> allFields = new ArrayList<>();
         Class<?> currentClass = cls;
         while (currentClass != null) {
@@ -253,7 +253,7 @@ public class FieldUtils {
      * @since 3.4
      */
     public static List<Field> getFieldsListWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
-        Validate.notNull(annotationCls, "The annotation class must not be null");
+        Validate.notNull(annotationCls, "annotationCls");
         final List<Field> allFields = getAllFieldsList(cls);
         final List<Field> annotatedFields = new ArrayList<>();
         for (final Field field : allFields) {
@@ -294,7 +294,7 @@ public class FieldUtils {
      *             if the field is not made accessible
      */
     public static Object readStaticField(final Field field, final boolean forceAccess) throws IllegalAccessException {
-        Validate.notNull(field, "The field must not be null");
+        Validate.notNull(field, "field");
         Validate.isTrue(Modifier.isStatic(field.getModifiers()), "The field '%s' is not static", field.getName());
         return readField(field, (Object) null, forceAccess);
     }
@@ -420,7 +420,7 @@ public class FieldUtils {
      *             if the field is not made accessible
      */
     public static Object readField(final Field field, final Object target, final boolean forceAccess) throws IllegalAccessException {
-        Validate.notNull(field, "The field must not be null");
+        Validate.notNull(field, "field");
         if (forceAccess && !field.isAccessible()) {
             field.setAccessible(true);
         } else {
@@ -464,7 +464,7 @@ public class FieldUtils {
      *             if the named field is not made accessible
      */
     public static Object readField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
-        Validate.notNull(target, "target object must not be null");
+        Validate.notNull(target, "target");
         final Class<?> cls = target.getClass();
         final Field field = getField(cls, fieldName, forceAccess);
         Validate.isTrue(field != null, "Cannot locate field %s on %s", fieldName, cls);
@@ -507,7 +507,7 @@ public class FieldUtils {
      *             if the field is not made accessible
      */
     public static Object readDeclaredField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
-        Validate.notNull(target, "target object must not be null");
+        Validate.notNull(target, "target");
         final Class<?> cls = target.getClass();
         final Field field = getDeclaredField(cls, fieldName, forceAccess);
         Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls, fieldName);
@@ -548,7 +548,7 @@ public class FieldUtils {
      *             if the field is not made accessible or is {@code final}
      */
     public static void writeStaticField(final Field field, final Object value, final boolean forceAccess) throws IllegalAccessException {
-        Validate.notNull(field, "The field must not be null");
+        Validate.notNull(field, "field");
         Validate.isTrue(Modifier.isStatic(field.getModifiers()), "The field %s.%s is not static", field.getDeclaringClass().getName(),
                 field.getName());
         writeField(field, (Object) null, value, forceAccess);
@@ -682,7 +682,7 @@ public class FieldUtils {
      */
     public static void writeField(final Field field, final Object target, final Object value, final boolean forceAccess)
             throws IllegalAccessException {
-        Validate.notNull(field, "The field must not be null");
+        Validate.notNull(field, "field");
         if (forceAccess && !field.isAccessible()) {
             field.setAccessible(true);
         } else {
@@ -722,7 +722,7 @@ public class FieldUtils {
      */
     @Deprecated
     public static void removeFinalModifier(final Field field, final boolean forceAccess) {
-        Validate.notNull(field, "The field must not be null");
+        Validate.notNull(field, "field");
 
         try {
             if (Modifier.isFinal(field.getModifiers())) {
@@ -791,7 +791,7 @@ public class FieldUtils {
      */
     public static void writeField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
             throws IllegalAccessException {
-        Validate.notNull(target, "target object must not be null");
+        Validate.notNull(target, "target");
         final Class<?> cls = target.getClass();
         final Field field = getField(cls, fieldName, forceAccess);
         Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
@@ -839,7 +839,7 @@ public class FieldUtils {
      */
     public static void writeDeclaredField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
             throws IllegalAccessException {
-        Validate.notNull(target, "target object must not be null");
+        Validate.notNull(target, "target");
         final Class<?> cls = target.getClass();
         final Field field = getDeclaredField(cls, fieldName, forceAccess);
         Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
diff --git a/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java b/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
index 3ddeac5..615a569 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
@@ -740,8 +740,8 @@ public class MethodUtils {
      */
     public static Method getMatchingMethod(final Class<?> cls, final String methodName,
             final Class<?>... parameterTypes) {
-        Validate.notNull(cls, "Null class not allowed.");
-        Validate.notEmpty(methodName, "Null or blank methodName not allowed.");
+        Validate.notNull(cls, "cls");
+        Validate.notEmpty(methodName, "methodName");
 
         // Address methods in superclasses
         Method[] methodArray = cls.getDeclaredMethods();
@@ -908,8 +908,8 @@ public class MethodUtils {
                                                             final Class<? extends Annotation> annotationCls,
                                                             final boolean searchSupers, final boolean ignoreAccess) {
 
-        Validate.notNull(cls, "The class must not be null");
-        Validate.notNull(annotationCls, "The annotation class must not be null");
+        Validate.notNull(cls, "cls");
+        Validate.notNull(annotationCls, "annotationCls");
         final List<Class<?>> classes = (searchSupers ? getAllSuperclassesAndInterfaces(cls)
                 : new ArrayList<>());
         classes.add(0, cls);
@@ -950,8 +950,8 @@ public class MethodUtils {
     public static <A extends Annotation> A getAnnotation(final Method method, final Class<A> annotationCls,
                                                          final boolean searchSupers, final boolean ignoreAccess) {
 
-        Validate.notNull(method, "The method must not be null");
-        Validate.notNull(annotationCls, "The annotation class must not be null");
+        Validate.notNull(method, "method");
+        Validate.notNull(annotationCls, "annotationCls");
         if (!ignoreAccess && !MemberUtils.isAccessible(method)) {
             return null;
         }
diff --git a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
index 5fe03af..7d90421 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
@@ -405,18 +405,18 @@ public class TypeUtils {
      * </p>
      *
      * @param cls the class whose type parameters are to be determined, not {@code null}
-     * @param superType the super type from which {@code cls}'s type
+     * @param superParameterizedType the super type from which {@code cls}'s type
      * arguments are to be determined, not {@code null}
      * @return a {@code Map} of the type assignments that could be determined
      * for the type variables in each type in the inheritance hierarchy from
      * {@code type} to {@code toClass} inclusive.
      */
     public static Map<TypeVariable<?>, Type> determineTypeArguments(final Class<?> cls,
-            final ParameterizedType superType) {
-        Validate.notNull(cls, "cls is null");
-        Validate.notNull(superType, "superType is null");
+            final ParameterizedType superParameterizedType) {
+        Validate.notNull(cls, "cls");
+        Validate.notNull(superParameterizedType, "superParameterizedType");
 
-        final Class<?> superClass = getRawType(superType);
+        final Class<?> superClass = getRawType(superParameterizedType);
 
         // compatibility check
         if (!isAssignable(cls, superClass)) {
@@ -424,7 +424,7 @@ public class TypeUtils {
         }
 
         if (cls.equals(superClass)) {
-            return getTypeArguments(superType, superClass, null);
+            return getTypeArguments(superParameterizedType, superClass, null);
         }
 
         // get the next class in the inheritance hierarchy
@@ -432,14 +432,14 @@ public class TypeUtils {
 
         // can only be a class or a parameterized type
         if (midType instanceof Class<?>) {
-            return determineTypeArguments((Class<?>) midType, superType);
+            return determineTypeArguments((Class<?>) midType, superParameterizedType);
         }
 
         final ParameterizedType midParameterizedType = (ParameterizedType) midType;
         final Class<?> midClass = getRawType(midParameterizedType);
         // get the type variables of the mid class that map to the type
         // arguments of the super class
-        final Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superType);
+        final Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superParameterizedType);
         // map the arguments of the mid type to the class type variables
         mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
 
@@ -580,7 +580,7 @@ public class TypeUtils {
      * @since 3.2
      */
     public static GenericArrayType genericArrayType(final Type componentType) {
-        return new GenericArrayTypeImpl(Validate.notNull(componentType, "componentType is null"));
+        return new GenericArrayTypeImpl(Validate.notNull(componentType, "componentType"));
     }
 
     /**
@@ -669,7 +669,7 @@ public class TypeUtils {
      * @return a non-empty array containing the bounds of the type variable.
      */
     public static Type[] getImplicitBounds(final TypeVariable<?> typeVariable) {
-        Validate.notNull(typeVariable, "typeVariable is null");
+        Validate.notNull(typeVariable, "typeVariable");
         final Type[] bounds = typeVariable.getBounds();
 
         return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
@@ -685,7 +685,7 @@ public class TypeUtils {
      * type.
      */
     public static Type[] getImplicitLowerBounds(final WildcardType wildcardType) {
-        Validate.notNull(wildcardType, "wildcardType is null");
+        Validate.notNull(wildcardType, "wildcardType");
         final Type[] bounds = wildcardType.getLowerBounds();
 
         return bounds.length == 0 ? new Type[] { null } : bounds;
@@ -702,7 +702,7 @@ public class TypeUtils {
      * type.
      */
     public static Type[] getImplicitUpperBounds(final WildcardType wildcardType) {
-        Validate.notNull(wildcardType, "wildcardType is null");
+        Validate.notNull(wildcardType, "wildcardType");
         final Type[] bounds = wildcardType.getUpperBounds();
 
         return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
@@ -1503,7 +1503,7 @@ public class TypeUtils {
      * redundant types.
      */
     public static Type[] normalizeUpperBounds(final Type[] bounds) {
-        Validate.notNull(bounds, "null value specified for bounds array");
+        Validate.notNull(bounds, "bounds");
         // don't bother if there's only one (or none) type
         if (bounds.length < 2) {
             return bounds;
@@ -1533,16 +1533,16 @@ public class TypeUtils {
      * Creates a parameterized type instance.
      *
      * @param rawClass the raw class to create a parameterized type instance for
-     * @param typeArgMappings the mapping used for parameterization
+     * @param typeVariableMap the map used for parameterization
      * @return {@link ParameterizedType}
      * @since 3.2
      */
     public static final ParameterizedType parameterize(final Class<?> rawClass,
-        final Map<TypeVariable<?>, Type> typeArgMappings) {
-        Validate.notNull(rawClass, "raw class is null");
-        Validate.notNull(typeArgMappings, "typeArgMappings is null");
+        final Map<TypeVariable<?>, Type> typeVariableMap) {
+        Validate.notNull(rawClass, "rawClass");
+        Validate.notNull(typeVariableMap, "typeVariableMap");
         return parameterizeWithOwner(null, rawClass,
-            extractTypeArgumentsFrom(typeArgMappings, rawClass.getTypeParameters()));
+            extractTypeArgumentsFrom(typeVariableMap, rawClass.getTypeParameters()));
     }
 
     /**
@@ -1597,16 +1597,16 @@ public class TypeUtils {
      *
      * @param owner the owning type
      * @param rawClass the raw class to create a parameterized type instance for
-     * @param typeArgMappings the mapping used for parameterization
+     * @param typeVariableMap the map used for parameterization
      * @return {@link ParameterizedType}
      * @since 3.2
      */
     public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass,
-        final Map<TypeVariable<?>, Type> typeArgMappings) {
-        Validate.notNull(rawClass, "raw class is null");
-        Validate.notNull(typeArgMappings, "typeArgMappings is null");
+        final Map<TypeVariable<?>, Type> typeVariableMap) {
+        Validate.notNull(rawClass, "rawClass");
+        Validate.notNull(typeVariableMap, "typeVariableMap");
         return parameterizeWithOwner(owner, rawClass,
-            extractTypeArgumentsFrom(typeArgMappings, rawClass.getTypeParameters()));
+            extractTypeArgumentsFrom(typeVariableMap, rawClass.getTypeParameters()));
     }
 
     /**
@@ -1621,7 +1621,7 @@ public class TypeUtils {
      */
     public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass,
         final Type... typeArguments) {
-        Validate.notNull(rawClass, "raw class is null");
+        Validate.notNull(rawClass, "rawClass");
         final Type useOwner;
         if (rawClass.getEnclosingClass() == null) {
             Validate.isTrue(owner == null, "no owner allowed for top-level %s", rawClass);
@@ -1665,14 +1665,14 @@ public class TypeUtils {
     /**
      * Formats a {@link TypeVariable} including its {@link GenericDeclaration}.
      *
-     * @param var the type variable to create a String representation for, not {@code null}
+     * @param typeVariable the type variable to create a String representation for, not {@code null}
      * @return String
      * @since 3.2
      */
-    public static String toLongString(final TypeVariable<?> var) {
-        Validate.notNull(var, "var is null");
+    public static String toLongString(final TypeVariable<?> typeVariable) {
+        Validate.notNull(typeVariable, "typeVariable");
         final StringBuilder buf = new StringBuilder();
-        final GenericDeclaration d = var.getGenericDeclaration();
+        final GenericDeclaration d = typeVariable.getGenericDeclaration();
         if (d instanceof Class<?>) {
             Class<?> c = (Class<?>) d;
             while (true) {
@@ -1688,7 +1688,7 @@ public class TypeUtils {
         } else {
             buf.append(d);
         }
-        return buf.append(':').append(typeVariableToString(var)).toString();
+        return buf.append(':').append(typeVariableToString(typeVariable)).toString();
     }
 
     private static <T> String toString(final T object) {
@@ -1730,22 +1730,22 @@ public class TypeUtils {
      * another type variable to be specified, the dependencies must be included
      * in {@code typeVarAssigns}.
      *
-     * @param typeVarAssigns specifies the potential types to be assigned to the
+     * @param typeVariableMap specifies the potential types to be assigned to the
      * type variables, not {@code null}.
      * @return whether or not the types can be assigned to their respective type
      * variables.
      */
-    public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVarAssigns) {
-        Validate.notNull(typeVarAssigns, "typeVarAssigns is null");
+    public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVariableMap) {
+        Validate.notNull(typeVariableMap, "typeVariableMap");
         // all types must be assignable to all the bounds of their mapped
         // type variable.
-        for (final Map.Entry<TypeVariable<?>, Type> entry : typeVarAssigns.entrySet()) {
+        for (final Map.Entry<TypeVariable<?>, Type> entry : typeVariableMap.entrySet()) {
             final TypeVariable<?> typeVar = entry.getKey();
             final Type type = entry.getValue();
 
             for (final Type bound : getImplicitBounds(typeVar)) {
-                if (!isAssignable(type, substituteTypeVariables(bound, typeVarAssigns),
-                        typeVarAssigns)) {
+                if (!isAssignable(type, substituteTypeVariables(bound, typeVariableMap),
+                        typeVariableMap)) {
                     return false;
                 }
             }
diff --git a/src/main/java/org/apache/commons/lang3/time/DateUtils.java b/src/main/java/org/apache/commons/lang3/time/DateUtils.java
index 917515d..3904062 100644
--- a/src/main/java/org/apache/commons/lang3/time/DateUtils.java
+++ b/src/main/java/org/apache/commons/lang3/time/DateUtils.java
@@ -1786,7 +1786,7 @@ public class DateUtils {
     }
 
     private static void validateDateNotNull(final Date date) {
-        Validate.notNull(date, "The date must not be null");
+        Validate.notNull(date, "date");
     }
 
     //-----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/lang3/time/FormatCache.java b/src/main/java/org/apache/commons/lang3/time/FormatCache.java
index a268203..14bc299 100644
--- a/src/main/java/org/apache/commons/lang3/time/FormatCache.java
+++ b/src/main/java/org/apache/commons/lang3/time/FormatCache.java
@@ -69,7 +69,7 @@ abstract class FormatCache<F extends Format> {
      * @throws IllegalArgumentException if pattern is invalid
      */
     public F getInstance(final String pattern, TimeZone timeZone, Locale locale) {
-        Validate.notNull(pattern, "pattern must not be null");
+        Validate.notNull(pattern, "pattern");
         if (timeZone == null) {
             timeZone = TimeZone.getDefault();
         }
diff --git a/src/test/java/org/apache/commons/lang3/CharRangeTest.java b/src/test/java/org/apache/commons/lang3/CharRangeTest.java
index 8d59a55..b3104fb 100644
--- a/src/test/java/org/apache/commons/lang3/CharRangeTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharRangeTest.java
@@ -312,7 +312,7 @@ public class CharRangeTest  {
     public void testContainsNullArg() {
         final CharRange range = CharRange.is('a');
         final NullPointerException e = assertThrows(NullPointerException.class, () -> range.contains(null));
-        assertEquals("The Range must not be null", e.getMessage());
+        assertEquals("range", e.getMessage());
     }
 
     @Test