1 /* 2 * Copyright (C) 2006 Google Inc. 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 com.google.inject; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 import static com.google.inject.internal.MoreTypes.canonicalize; 22 23 import com.google.common.collect.ImmutableList; 24 import com.google.inject.internal.MoreTypes; 25 import com.google.inject.util.Types; 26 import java.lang.reflect.Constructor; 27 import java.lang.reflect.Field; 28 import java.lang.reflect.GenericArrayType; 29 import java.lang.reflect.Member; 30 import java.lang.reflect.Method; 31 import java.lang.reflect.ParameterizedType; 32 import java.lang.reflect.Type; 33 import java.lang.reflect.TypeVariable; 34 import java.lang.reflect.WildcardType; 35 import java.util.List; 36 37 /** 38 * Represents a generic type {@code T}. Java doesn't yet provide a way to represent generic types, 39 * so this class does. Forces clients to create a subclass of this class which enables retrieval of 40 * the type information even at runtime. 41 * 42 * <p>For example, to create a type literal for {@code List<String>}, you can create an empty 43 * anonymous inner class: 44 * 45 * <p>{@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};} 46 * 47 * <p>Along with modeling generic types, this class can resolve type parameters. For example, to 48 * figure out what type {@code keySet()} returns on a {@code Map<Integer, String>}, use this code: 49 * 50 * <pre>{@code 51 * TypeLiteral<Map<Integer, String>> mapType 52 * = new TypeLiteral<Map<Integer, String>>() {}; 53 * TypeLiteral<?> keySetType 54 * = mapType.getReturnType(Map.class.getMethod("keySet")); 55 * System.out.println(keySetType); // prints "Set<Integer>" 56 * }</pre> 57 * 58 * @author crazybob (at) google.com (Bob Lee) 59 * @author jessewilson (at) google.com (Jesse Wilson) 60 */ 61 public class TypeLiteral<T> { 62 63 final Class<? super T> rawType; 64 final Type type; 65 final int hashCode; 66 67 /** 68 * Constructs a new type literal. Derives represented class from type parameter. 69 * 70 * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the 71 * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure. 72 */ 73 @SuppressWarnings("unchecked") 74 protected TypeLiteral() { 75 this.type = getSuperclassTypeParameter(getClass()); 76 this.rawType = (Class<? super T>) MoreTypes.getRawType(type); 77 this.hashCode = type.hashCode(); 78 } 79 80 /** Unsafe. Constructs a type literal manually. */ 81 @SuppressWarnings("unchecked") 82 TypeLiteral(Type type) { 83 this.type = canonicalize(checkNotNull(type, "type")); 84 this.rawType = (Class<? super T>) MoreTypes.getRawType(this.type); 85 this.hashCode = this.type.hashCode(); 86 } 87 88 /** 89 * Returns the type from super class's type parameter in {@link MoreTypes#canonicalize(Type) 90 * canonical form}. 91 */ 92 static Type getSuperclassTypeParameter(Class<?> subclass) { 93 Type superclass = subclass.getGenericSuperclass(); 94 if (superclass instanceof Class) { 95 throw new RuntimeException("Missing type parameter."); 96 } 97 ParameterizedType parameterized = (ParameterizedType) superclass; 98 return canonicalize(parameterized.getActualTypeArguments()[0]); 99 } 100 101 /** Gets type literal from super class's type parameter. */ 102 static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) { 103 return new TypeLiteral<Object>(getSuperclassTypeParameter(subclass)); 104 } 105 106 /** 107 * Returns the raw (non-generic) type for this type. 108 * 109 * @since 2.0 110 */ 111 public final Class<? super T> getRawType() { 112 return rawType; 113 } 114 115 /** Gets underlying {@code Type} instance. */ 116 public final Type getType() { 117 return type; 118 } 119 120 /** Gets the type of this type's provider. */ 121 @SuppressWarnings("unchecked") 122 final TypeLiteral<Provider<T>> providerType() { 123 // This cast is safe and wouldn't generate a warning if Type had a type 124 // parameter. 125 return (TypeLiteral<Provider<T>>) get(Types.providerOf(getType())); 126 } 127 128 @Override 129 public final int hashCode() { 130 return this.hashCode; 131 } 132 133 @Override 134 public final boolean equals(Object o) { 135 return o instanceof TypeLiteral<?> && MoreTypes.equals(type, ((TypeLiteral) o).type); 136 } 137 138 @Override 139 public final String toString() { 140 return MoreTypes.typeToString(type); 141 } 142 143 /** Gets type literal for the given {@code Type} instance. */ 144 public static TypeLiteral<?> get(Type type) { 145 return new TypeLiteral<Object>(type); 146 } 147 148 /** Gets type literal for the given {@code Class} instance. */ 149 public static <T> TypeLiteral<T> get(Class<T> type) { 150 return new TypeLiteral<T>(type); 151 } 152 153 /** Returns an immutable list of the resolved types. */ 154 private List<TypeLiteral<?>> resolveAll(Type[] types) { 155 TypeLiteral<?>[] result = new TypeLiteral<?>[types.length]; 156 for (int t = 0; t < types.length; t++) { 157 result[t] = resolve(types[t]); 158 } 159 return ImmutableList.copyOf(result); 160 } 161 162 /** Resolves known type parameters in {@code toResolve} and returns the result. */ 163 TypeLiteral<?> resolve(Type toResolve) { 164 return TypeLiteral.get(resolveType(toResolve)); 165 } 166 167 Type resolveType(Type toResolve) { 168 // this implementation is made a little more complicated in an attempt to avoid object-creation 169 while (true) { 170 if (toResolve instanceof TypeVariable) { 171 TypeVariable original = (TypeVariable) toResolve; 172 toResolve = MoreTypes.resolveTypeVariable(type, rawType, original); 173 if (toResolve == original) { 174 return toResolve; 175 } 176 177 } else if (toResolve instanceof GenericArrayType) { 178 GenericArrayType original = (GenericArrayType) toResolve; 179 Type componentType = original.getGenericComponentType(); 180 Type newComponentType = resolveType(componentType); 181 return componentType == newComponentType ? original : Types.arrayOf(newComponentType); 182 183 } else if (toResolve instanceof ParameterizedType) { 184 ParameterizedType original = (ParameterizedType) toResolve; 185 Type ownerType = original.getOwnerType(); 186 Type newOwnerType = resolveType(ownerType); 187 boolean changed = newOwnerType != ownerType; 188 189 Type[] args = original.getActualTypeArguments(); 190 for (int t = 0, length = args.length; t < length; t++) { 191 Type resolvedTypeArgument = resolveType(args[t]); 192 if (resolvedTypeArgument != args[t]) { 193 if (!changed) { 194 args = args.clone(); 195 changed = true; 196 } 197 args[t] = resolvedTypeArgument; 198 } 199 } 200 201 return changed 202 ? Types.newParameterizedTypeWithOwner(newOwnerType, original.getRawType(), args) 203 : original; 204 205 } else if (toResolve instanceof WildcardType) { 206 WildcardType original = (WildcardType) toResolve; 207 Type[] originalLowerBound = original.getLowerBounds(); 208 Type[] originalUpperBound = original.getUpperBounds(); 209 210 if (originalLowerBound.length == 1) { 211 Type lowerBound = resolveType(originalLowerBound[0]); 212 if (lowerBound != originalLowerBound[0]) { 213 return Types.supertypeOf(lowerBound); 214 } 215 } else if (originalUpperBound.length == 1) { 216 Type upperBound = resolveType(originalUpperBound[0]); 217 if (upperBound != originalUpperBound[0]) { 218 return Types.subtypeOf(upperBound); 219 } 220 } 221 return original; 222 223 } else { 224 return toResolve; 225 } 226 } 227 } 228 229 /** 230 * Returns the generic form of {@code supertype}. For example, if this is {@code 231 * ArrayList<String>}, this returns {@code Iterable<String>} given the input {@code 232 * Iterable.class}. 233 * 234 * @param supertype a superclass of, or interface implemented by, this. 235 * @since 2.0 236 */ 237 public TypeLiteral<?> getSupertype(Class<?> supertype) { 238 checkArgument( 239 supertype.isAssignableFrom(rawType), "%s is not a supertype of %s", supertype, this.type); 240 return resolve(MoreTypes.getGenericSupertype(type, rawType, supertype)); 241 } 242 243 /** 244 * Returns the resolved generic type of {@code field}. 245 * 246 * @param field a field defined by this or any superclass. 247 * @since 2.0 248 */ 249 public TypeLiteral<?> getFieldType(Field field) { 250 checkArgument( 251 field.getDeclaringClass().isAssignableFrom(rawType), 252 "%s is not defined by a supertype of %s", 253 field, 254 type); 255 return resolve(field.getGenericType()); 256 } 257 258 /** 259 * Returns the resolved generic parameter types of {@code methodOrConstructor}. 260 * 261 * @param methodOrConstructor a method or constructor defined by this or any supertype. 262 * @since 2.0 263 */ 264 public List<TypeLiteral<?>> getParameterTypes(Member methodOrConstructor) { 265 Type[] genericParameterTypes; 266 267 if (methodOrConstructor instanceof Method) { 268 Method method = (Method) methodOrConstructor; 269 checkArgument( 270 method.getDeclaringClass().isAssignableFrom(rawType), 271 "%s is not defined by a supertype of %s", 272 method, 273 type); 274 genericParameterTypes = method.getGenericParameterTypes(); 275 276 } else if (methodOrConstructor instanceof Constructor) { 277 Constructor<?> constructor = (Constructor<?>) methodOrConstructor; 278 checkArgument( 279 constructor.getDeclaringClass().isAssignableFrom(rawType), 280 "%s does not construct a supertype of %s", 281 constructor, 282 type); 283 genericParameterTypes = constructor.getGenericParameterTypes(); 284 285 } else { 286 throw new IllegalArgumentException("Not a method or a constructor: " + methodOrConstructor); 287 } 288 289 return resolveAll(genericParameterTypes); 290 } 291 292 /** 293 * Returns the resolved generic exception types thrown by {@code constructor}. 294 * 295 * @param methodOrConstructor a method or constructor defined by this or any supertype. 296 * @since 2.0 297 */ 298 public List<TypeLiteral<?>> getExceptionTypes(Member methodOrConstructor) { 299 Type[] genericExceptionTypes; 300 301 if (methodOrConstructor instanceof Method) { 302 Method method = (Method) methodOrConstructor; 303 checkArgument( 304 method.getDeclaringClass().isAssignableFrom(rawType), 305 "%s is not defined by a supertype of %s", 306 method, 307 type); 308 genericExceptionTypes = method.getGenericExceptionTypes(); 309 310 } else if (methodOrConstructor instanceof Constructor) { 311 Constructor<?> constructor = (Constructor<?>) methodOrConstructor; 312 checkArgument( 313 constructor.getDeclaringClass().isAssignableFrom(rawType), 314 "%s does not construct a supertype of %s", 315 constructor, 316 type); 317 genericExceptionTypes = constructor.getGenericExceptionTypes(); 318 319 } else { 320 throw new IllegalArgumentException("Not a method or a constructor: " + methodOrConstructor); 321 } 322 323 return resolveAll(genericExceptionTypes); 324 } 325 326 /** 327 * Returns the resolved generic return type of {@code method}. 328 * 329 * @param method a method defined by this or any supertype. 330 * @since 2.0 331 */ 332 public TypeLiteral<?> getReturnType(Method method) { 333 checkArgument( 334 method.getDeclaringClass().isAssignableFrom(rawType), 335 "%s is not defined by a supertype of %s", 336 method, 337 type); 338 return resolve(method.getGenericReturnType()); 339 } 340 } 341