1 /* 2 * Copyright 2002-2010 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.springframework.util; 18 19 import java.lang.reflect.GenericArrayType; 20 import java.lang.reflect.ParameterizedType; 21 import java.lang.reflect.Type; 22 import java.lang.reflect.WildcardType; 23 24 import org.springframework.util.ClassUtils; 25 26 /** 27 * Utility to work with Java 5 generic type parameters. 28 * Mainly for internal use within the framework. 29 * 30 * @author Ramnivas Laddad 31 * @author Juergen Hoeller 32 * @author Chris Beams 33 * @since 2.0.7 34 */ 35 public abstract class TypeUtils { 36 37 /** 38 * Check if the right-hand side type may be assigned to the left-hand side 39 * type following the Java generics rules. 40 * @param lhsType the target type 41 * @param rhsType the value type that should be assigned to the target type 42 * @return true if rhs is assignable to lhs 43 */ isAssignable(Type lhsType, Type rhsType)44 public static boolean isAssignable(Type lhsType, Type rhsType) { 45 Assert.notNull(lhsType, "Left-hand side type must not be null"); 46 Assert.notNull(rhsType, "Right-hand side type must not be null"); 47 48 // all types are assignable to themselves and to class Object 49 if (lhsType.equals(rhsType) || lhsType.equals(Object.class)) { 50 return true; 51 } 52 53 if (lhsType instanceof Class<?>) { 54 Class<?> lhsClass = (Class<?>) lhsType; 55 56 // just comparing two classes 57 if (rhsType instanceof Class<?>) { 58 return ClassUtils.isAssignable(lhsClass, (Class<?>) rhsType); 59 } 60 61 if (rhsType instanceof ParameterizedType) { 62 Type rhsRaw = ((ParameterizedType) rhsType).getRawType(); 63 64 // a parameterized type is always assignable to its raw class type 65 if (rhsRaw instanceof Class<?>) { 66 return ClassUtils.isAssignable(lhsClass, (Class<?>) rhsRaw); 67 } 68 } 69 else if (lhsClass.isArray() && rhsType instanceof GenericArrayType) { 70 Type rhsComponent = ((GenericArrayType) rhsType).getGenericComponentType(); 71 72 return isAssignable(lhsClass.getComponentType(), rhsComponent); 73 } 74 } 75 76 // parameterized types are only assignable to other parameterized types and class types 77 if (lhsType instanceof ParameterizedType) { 78 if (rhsType instanceof Class<?>) { 79 Type lhsRaw = ((ParameterizedType) lhsType).getRawType(); 80 81 if (lhsRaw instanceof Class<?>) { 82 return ClassUtils.isAssignable((Class<?>) lhsRaw, (Class<?>) rhsType); 83 } 84 } 85 else if (rhsType instanceof ParameterizedType) { 86 return isAssignable((ParameterizedType) lhsType, (ParameterizedType) rhsType); 87 } 88 } 89 90 if (lhsType instanceof GenericArrayType) { 91 Type lhsComponent = ((GenericArrayType) lhsType).getGenericComponentType(); 92 93 if (rhsType instanceof Class<?>) { 94 Class<?> rhsClass = (Class<?>) rhsType; 95 96 if (rhsClass.isArray()) { 97 return isAssignable(lhsComponent, rhsClass.getComponentType()); 98 } 99 } 100 else if (rhsType instanceof GenericArrayType) { 101 Type rhsComponent = ((GenericArrayType) rhsType).getGenericComponentType(); 102 103 return isAssignable(lhsComponent, rhsComponent); 104 } 105 } 106 107 if (lhsType instanceof WildcardType) { 108 return isAssignable((WildcardType) lhsType, rhsType); 109 } 110 111 return false; 112 } 113 isAssignable(ParameterizedType lhsType, ParameterizedType rhsType)114 private static boolean isAssignable(ParameterizedType lhsType, ParameterizedType rhsType) { 115 if (lhsType.equals(rhsType)) { 116 return true; 117 } 118 119 Type[] lhsTypeArguments = lhsType.getActualTypeArguments(); 120 Type[] rhsTypeArguments = rhsType.getActualTypeArguments(); 121 122 if (lhsTypeArguments.length != rhsTypeArguments.length) { 123 return false; 124 } 125 126 for (int size = lhsTypeArguments.length, i = 0; i < size; ++i) { 127 Type lhsArg = lhsTypeArguments[i]; 128 Type rhsArg = rhsTypeArguments[i]; 129 130 if (!lhsArg.equals(rhsArg) && 131 !(lhsArg instanceof WildcardType && isAssignable((WildcardType) lhsArg, rhsArg))) { 132 return false; 133 } 134 } 135 136 return true; 137 } 138 isAssignable(WildcardType lhsType, Type rhsType)139 private static boolean isAssignable(WildcardType lhsType, Type rhsType) { 140 Type[] lUpperBounds = lhsType.getUpperBounds(); 141 142 // supply the implicit upper bound if none are specified 143 if (lUpperBounds.length == 0) { 144 lUpperBounds = new Type[] { Object.class }; 145 } 146 147 Type[] lLowerBounds = lhsType.getLowerBounds(); 148 149 // supply the implicit lower bound if none are specified 150 if (lLowerBounds.length == 0) { 151 lLowerBounds = new Type[] { null }; 152 } 153 154 if (rhsType instanceof WildcardType) { 155 // both the upper and lower bounds of the right-hand side must be 156 // completely enclosed in the upper and lower bounds of the left- 157 // hand side. 158 WildcardType rhsWcType = (WildcardType) rhsType; 159 Type[] rUpperBounds = rhsWcType.getUpperBounds(); 160 161 if (rUpperBounds.length == 0) { 162 rUpperBounds = new Type[] { Object.class }; 163 } 164 165 Type[] rLowerBounds = rhsWcType.getLowerBounds(); 166 167 if (rLowerBounds.length == 0) { 168 rLowerBounds = new Type[] { null }; 169 } 170 171 for (Type lBound : lUpperBounds) { 172 for (Type rBound : rUpperBounds) { 173 if (!isAssignableBound(lBound, rBound)) { 174 return false; 175 } 176 } 177 178 for (Type rBound : rLowerBounds) { 179 if (!isAssignableBound(lBound, rBound)) { 180 return false; 181 } 182 } 183 } 184 185 for (Type lBound : lLowerBounds) { 186 for (Type rBound : rUpperBounds) { 187 if (!isAssignableBound(rBound, lBound)) { 188 return false; 189 } 190 } 191 192 for (Type rBound : rLowerBounds) { 193 if (!isAssignableBound(rBound, lBound)) { 194 return false; 195 } 196 } 197 } 198 } 199 else { 200 for (Type lBound : lUpperBounds) { 201 if (!isAssignableBound(lBound, rhsType)) { 202 return false; 203 } 204 } 205 206 for (Type lBound : lLowerBounds) { 207 if (!isAssignableBound(rhsType, lBound)) { 208 return false; 209 } 210 } 211 } 212 213 return true; 214 } 215 isAssignableBound(Type lhsType, Type rhsType)216 public static boolean isAssignableBound(Type lhsType, Type rhsType) { 217 if (rhsType == null) { 218 return true; 219 } 220 221 if (lhsType == null) { 222 return false; 223 } 224 return isAssignable(lhsType, rhsType); 225 } 226 227 } 228