Reflection Java

/*
 * Copyright 2002-2007 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.
 */
import java.beans.Introspector;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import junit.framework.Assert;
import sun.rmi.runtime.Log;
/**
 * Utility to work with Java 5 generic type parameters.
 * Mainly for internal use within the framework.
 *
 * @author Ramnivas Laddad
 * @author Juergen Hoeller
 * @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) {
    if (lhsType.equals(rhsType)) {
      return true;
    }
    if (lhsType instanceof Class && rhsType instanceof Class) {
      return ClassUtils.isAssignable((Class) lhsType, (Class) rhsType);
    }
    if (lhsType instanceof ParameterizedType && rhsType instanceof ParameterizedType) {
      return isAssignable((ParameterizedType) lhsType, (ParameterizedType) rhsType);
    }
    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[] upperBounds = lhsType.getUpperBounds();
    Type[] lowerBounds = lhsType.getLowerBounds();
    for (int size = upperBounds.length, i = 0; i < size; ++i) {
      if (!isAssignable(upperBounds[i], rhsType)) {
        return false;
      }
    }
    for (int size = lowerBounds.length, i = 0; i < size; ++i) {
      if (!isAssignable(rhsType, lowerBounds[i])) {
        return false;
      }
    }
    return true;
  }
}
/*
 * Copyright 2002-2007 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.
 */
/**
 * Miscellaneous class utility methods. Mainly for internal use within the
 * framework; consider Jakarta's Commons Lang for a more comprehensive suite
 * of class utilities.
 *
 * @author Keith Donald
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @since 1.1
 * @see TypeUtils
 * @see ReflectionUtils
 */
 abstract class ClassUtils {
  /** Suffix for array class names: "[]" */
  public static final String ARRAY_SUFFIX = "[]";
  /** Prefix for internal array class names: "[L" */
  private static final String INTERNAL_ARRAY_PREFIX = "[L";
  /** The package separator character '.' */
  private static final char PACKAGE_SEPARATOR = '.';
  /** The inner class separator character '$' */
  private static final char INNER_CLASS_SEPARATOR = '$';
  /** The CGLIB class separator character "$$" */
  public static final String CGLIB_CLASS_SEPARATOR = "$$";
  /** The ".class" file suffix */
  public static final String CLASS_FILE_SUFFIX = ".class";
  /**
   * Map with primitive wrapper type as key and corresponding primitive
   * type as value, for example: Integer.class -> int.class.
   */
  private static final Map primitiveWrapperTypeMap = new HashMap(8);
  /**
   * Map with primitive type name as key and corresponding primitive
   * type as value, for example: "int" -> "int.class".
   */
  private static final Map primitiveTypeNameMap = new HashMap(16);
  static {
    primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
    primitiveWrapperTypeMap.put(Byte.class, byte.class);
    primitiveWrapperTypeMap.put(Character.class, char.class);
    primitiveWrapperTypeMap.put(Double.class, double.class);
    primitiveWrapperTypeMap.put(Float.class, float.class);
    primitiveWrapperTypeMap.put(Integer.class, int.class);
    primitiveWrapperTypeMap.put(Long.class, long.class);
    primitiveWrapperTypeMap.put(Short.class, short.class);
    Set primitiveTypeNames = new HashSet(16);
    primitiveTypeNames.addAll(primitiveWrapperTypeMap.values());
    primitiveTypeNames.addAll(Arrays.asList(new Class[] {
        boolean[].class, byte[].class, char[].class, double[].class,
        float[].class, int[].class, long[].class, short[].class}));
    for (Iterator it = primitiveTypeNames.iterator(); it.hasNext();) {
      Class primitiveClass = (Class) it.next();
      primitiveTypeNameMap.put(primitiveClass.getName(), primitiveClass);
    }
  }
  /**
   * Check if the right-hand side type may be assigned to the left-hand side
   * type, assuming setting by reflection. Considers primitive wrapper
   * classes as assignable to the corresponding primitive types.
   * @param lhsType the target type
   * @param rhsType the value type that should be assigned to the target type
   * @return if the target type is assignable from the value type
   * @see TypeUtils#isAssignable
   */
  public static boolean isAssignable(Class lhsType, Class rhsType) {
    return (lhsType.isAssignableFrom(rhsType) ||
        lhsType.equals(primitiveWrapperTypeMap.get(rhsType)));
  }
}