Package org.springframework.util

Source Code of org.springframework.util.TypeUtils

/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.util;

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;

import org.springframework.util.ClassUtils;

/**
* Utility to work with Java 5 generic type parameters.
* Mainly for internal use within the framework.
*
* @author Ramnivas Laddad
* @author Juergen Hoeller
* @author Chris Beams
* @since 2.0.7
*/
public abstract class TypeUtils {

  /**
   * Check if the right-hand side type may be assigned to the left-hand side
   * type following the Java generics rules.
   * @param lhsType the target type
   * @param rhsType the value type that should be assigned to the target type
   * @return true if rhs is assignable to lhs
   */
  public static boolean isAssignable(Type lhsType, Type rhsType) {
    Assert.notNull(lhsType, "Left-hand side type must not be null");
    Assert.notNull(rhsType, "Right-hand side type must not be null");

    // all types are assignable to themselves and to class Object
    if (lhsType.equals(rhsType) || lhsType.equals(Object.class)) {
      return true;
    }

    if (lhsType instanceof Class<?>) {
      Class<?> lhsClass = (Class<?>) lhsType;

      // just comparing two classes
      if (rhsType instanceof Class<?>) {
        return ClassUtils.isAssignable(lhsClass, (Class<?>) rhsType);
      }

      if (rhsType instanceof ParameterizedType) {
        Type rhsRaw = ((ParameterizedType) rhsType).getRawType();

        // a parameterized type is always assignable to its raw class type
        if (rhsRaw instanceof Class<?>) {
          return ClassUtils.isAssignable(lhsClass, (Class<?>) rhsRaw);
        }
      }
      else if (lhsClass.isArray() && rhsType instanceof GenericArrayType) {
        Type rhsComponent = ((GenericArrayType) rhsType).getGenericComponentType();

        return isAssignable(lhsClass.getComponentType(), rhsComponent);
      }
    }

    // parameterized types are only assignable to other parameterized types and class types
    if (lhsType instanceof ParameterizedType) {
      if (rhsType instanceof Class<?>) {
        Type lhsRaw = ((ParameterizedType) lhsType).getRawType();

        if (lhsRaw instanceof Class<?>) {
          return ClassUtils.isAssignable((Class<?>) lhsRaw, (Class<?>) rhsType);
        }
      }
      else if (rhsType instanceof ParameterizedType) {
        return isAssignable((ParameterizedType) lhsType, (ParameterizedType) rhsType);
      }
    }

    if (lhsType instanceof GenericArrayType) {
      Type lhsComponent = ((GenericArrayType) lhsType).getGenericComponentType();

      if (rhsType instanceof Class<?>) {
        Class<?> rhsClass = (Class<?>) rhsType;

        if (rhsClass.isArray()) {
          return isAssignable(lhsComponent, rhsClass.getComponentType());
        }
      }
      else if (rhsType instanceof GenericArrayType) {
        Type rhsComponent = ((GenericArrayType) rhsType).getGenericComponentType();

        return isAssignable(lhsComponent, rhsComponent);
      }
    }

    if (lhsType instanceof WildcardType) {
      return isAssignable((WildcardType) lhsType, rhsType);
    }

    return false;
  }

  private static boolean isAssignable(ParameterizedType lhsType, ParameterizedType rhsType) {
    if (lhsType.equals(rhsType)) {
      return true;
    }

    Type[] lhsTypeArguments = lhsType.getActualTypeArguments();
    Type[] rhsTypeArguments = rhsType.getActualTypeArguments();

    if (lhsTypeArguments.length != rhsTypeArguments.length) {
      return false;
    }

    for (int size = lhsTypeArguments.length, i = 0; i < size; ++i) {
      Type lhsArg = lhsTypeArguments[i];
      Type rhsArg = rhsTypeArguments[i];

      if (!lhsArg.equals(rhsArg) &&
          !(lhsArg instanceof WildcardType && isAssignable((WildcardType) lhsArg, rhsArg))) {
        return false;
      }
    }

    return true;
  }

  private static boolean isAssignable(WildcardType lhsType, Type rhsType) {
    Type[] lUpperBounds = lhsType.getUpperBounds();

    // supply the implicit upper bound if none are specified
    if (lUpperBounds.length == 0) {
      lUpperBounds = new Type[] { Object.class };
    }

    Type[] lLowerBounds = lhsType.getLowerBounds();

    // supply the implicit lower bound if none are specified
    if (lLowerBounds.length == 0) {
      lLowerBounds = new Type[] { null };
    }

    if (rhsType instanceof WildcardType) {
      // both the upper and lower bounds of the right-hand side must be
      // completely enclosed in the upper and lower bounds of the left-
      // hand side.
      WildcardType rhsWcType = (WildcardType) rhsType;
      Type[] rUpperBounds = rhsWcType.getUpperBounds();

      if (rUpperBounds.length == 0) {
        rUpperBounds = new Type[] { Object.class };
      }

      Type[] rLowerBounds = rhsWcType.getLowerBounds();

      if (rLowerBounds.length == 0) {
        rLowerBounds = new Type[] { null };
      }

      for (Type lBound : lUpperBounds) {
        for (Type rBound : rUpperBounds) {
          if (!isAssignableBound(lBound, rBound)) {
            return false;
          }
        }

        for (Type rBound : rLowerBounds) {
          if (!isAssignableBound(lBound, rBound)) {
            return false;
          }
        }
      }

      for (Type lBound : lLowerBounds) {
        for (Type rBound : rUpperBounds) {
          if (!isAssignableBound(rBound, lBound)) {
            return false;
          }
        }

        for (Type rBound : rLowerBounds) {
          if (!isAssignableBound(rBound, lBound)) {
            return false;
          }
        }
      }
    }
    else {
      for (Type lBound : lUpperBounds) {
        if (!isAssignableBound(lBound, rhsType)) {
          return false;
        }
      }

      for (Type lBound : lLowerBounds) {
        if (!isAssignableBound(rhsType, lBound)) {
          return false;
        }
      }
    }

    return true;
  }
 
  public static boolean isAssignableBound(Type lhsType, Type rhsType) {
    if (rhsType == null) {
      return true;
    }

    if (lhsType == null) {
      return false;
    }
    return isAssignable(lhsType, rhsType);
  }

}
TOP

Related Classes of org.springframework.util.TypeUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.