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