summaryrefslogtreecommitdiffstats
path: root/guava/src/com/google/common/reflect
diff options
context:
space:
mode:
Diffstat (limited to 'guava/src/com/google/common/reflect')
-rw-r--r--guava/src/com/google/common/reflect/AbstractInvocationHandler.java82
-rw-r--r--guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java138
-rw-r--r--guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java89
-rw-r--r--guava/src/com/google/common/reflect/Reflection.java103
-rw-r--r--guava/src/com/google/common/reflect/TypeCapture.java38
-rw-r--r--guava/src/com/google/common/reflect/TypeParameter.java70
-rw-r--r--guava/src/com/google/common/reflect/TypeResolver.java389
-rw-r--r--guava/src/com/google/common/reflect/TypeToInstanceMap.java92
-rw-r--r--guava/src/com/google/common/reflect/TypeToken.java1086
-rw-r--r--guava/src/com/google/common/reflect/Types.java518
-rw-r--r--guava/src/com/google/common/reflect/package-info.java23
11 files changed, 2628 insertions, 0 deletions
diff --git a/guava/src/com/google/common/reflect/AbstractInvocationHandler.java b/guava/src/com/google/common/reflect/AbstractInvocationHandler.java
new file mode 100644
index 0000000..8453b7c
--- /dev/null
+++ b/guava/src/com/google/common/reflect/AbstractInvocationHandler.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2012 The Guava 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 com.google.common.reflect;
+
+import com.google.common.annotations.Beta;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+import javax.annotation.Nullable;
+
+/**
+ * Abstract implementation of {@link InvocationHandler} that handles {@link Object#equals},
+ * {@link Object#hashCode} and {@link Object#toString}.
+ *
+ * @author Ben Yu
+ * @since 12.0
+ */
+@Beta
+public abstract class AbstractInvocationHandler implements InvocationHandler {
+
+ private static final Object[] NO_ARGS = {};
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>{@link Object#equals}, {@link Object#hashCode} are implemented according to referential
+ * equality (the default behavior of {@link Object}). {@link Object#toString} delegates to
+ * {@link #toString} that can be overridden by subclasses.
+ */
+ @Override public final Object invoke(Object proxy, Method method, @Nullable Object[] args)
+ throws Throwable {
+ if (args == null) {
+ args = NO_ARGS;
+ }
+ if (args.length == 0 && method.getName().equals("hashCode")) {
+ return System.identityHashCode(proxy);
+ }
+ if (args.length == 1
+ && method.getName().equals("equals")
+ && method.getParameterTypes()[0] == Object.class) {
+ return proxy == args[0];
+ }
+ if (args.length == 0 && method.getName().equals("toString")) {
+ return toString();
+ }
+ return handleInvocation(proxy, method, args);
+ }
+
+ /**
+ * {@link #invoke} delegates to this method upon any method invocation on the proxy instance,
+ * except {@link Object#equals}, {@link Object#hashCode} and {@link Object#toString}. The result
+ * will be returned as the proxied method's return value.
+ *
+ * <p>Unlike {@link #invoke}, {@code args} will never be null. When the method has no parameter,
+ * an empty array is passed in.
+ */
+ protected abstract Object handleInvocation(Object proxy, Method method, Object[] args)
+ throws Throwable;
+
+ /**
+ * The dynamic proxies' {@link Object#toString} will delegate to this method. Subclasses can
+ * override this to provide custom string representation of the proxies.
+ */
+ @Override public String toString() {
+ return super.toString();
+ }
+}
diff --git a/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java b/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java
new file mode 100644
index 0000000..43e5e1e
--- /dev/null
+++ b/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012 The Guava 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 com.google.common.reflect;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ForwardingMap;
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Map;
+
+/**
+ * A type-to-instance map backed by an {@link ImmutableMap}. See also {@link
+ * MutableTypeToInstanceMap}.
+ *
+ * @author Ben Yu
+ * @since 13.0
+ */
+@Beta
+public final class ImmutableTypeToInstanceMap<B> extends ForwardingMap<TypeToken<? extends B>, B>
+ implements TypeToInstanceMap<B> {
+
+ /** Returns an empty type to instance map. */
+ public static <B> ImmutableTypeToInstanceMap<B> of() {
+ return new ImmutableTypeToInstanceMap<B>(ImmutableMap.<TypeToken<? extends B>, B>of());
+ }
+
+ /** Returns a new builder. */
+ public static <B> Builder<B> builder() {
+ return new Builder<B>();
+ }
+
+ /**
+ * A builder for creating immutable type-to-instance maps. Example:
+ * <pre> {@code
+ *
+ * static final ImmutableTypeToInstanceMap<Handler<?>> HANDLERS =
+ * ImmutableTypeToInstanceMap.<Handler<?>>builder()
+ * .put(new TypeToken<Handler<Foo>>() {}, new FooHandler())
+ * .put(new TypeToken<Handler<Bar>>() {}, new SubBarHandler())
+ * .build();}</pre>
+ *
+ * After invoking {@link #build()} it is still possible to add more entries
+ * and build again. Thus each map generated by this builder will be a superset
+ * of any map generated before it.
+ *
+ * @since 13.0
+ */
+ @Beta
+ public static final class Builder<B> {
+ private final ImmutableMap.Builder<TypeToken<? extends B>, B> mapBuilder
+ = ImmutableMap.builder();
+
+ private Builder() {}
+
+ /**
+ * Associates {@code key} with {@code value} in the built map. Duplicate
+ * keys are not allowed, and will cause {@link #build} to fail.
+ */
+ public <T extends B> Builder<B> put(Class<T> key, T value) {
+ mapBuilder.put(TypeToken.of(key), value);
+ return this;
+ }
+
+ /**
+ * Associates {@code key} with {@code value} in the built map. Duplicate
+ * keys are not allowed, and will cause {@link #build} to fail.
+ */
+ public <T extends B> Builder<B> put(TypeToken<T> key, T value) {
+ mapBuilder.put(key.rejectTypeVariables(), value);
+ return this;
+ }
+
+ /**
+ * Returns a new immutable type-to-instance map containing the entries
+ * provided to this builder.
+ *
+ * @throws IllegalArgumentException if duplicate keys were added
+ */
+ public ImmutableTypeToInstanceMap<B> build() {
+ return new ImmutableTypeToInstanceMap<B>(mapBuilder.build());
+ }
+ }
+
+ private final ImmutableMap<TypeToken<? extends B>, B> delegate;
+
+ private ImmutableTypeToInstanceMap(ImmutableMap<TypeToken<? extends B>, B> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override public <T extends B> T getInstance(TypeToken<T> type) {
+ return trustedGet(type.rejectTypeVariables());
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override public <T extends B> T putInstance(TypeToken<T> type, T value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public <T extends B> T getInstance(Class<T> type) {
+ return trustedGet(TypeToken.of(type));
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override public <T extends B> T putInstance(Class<T> type, T value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override protected Map<TypeToken<? extends B>, B> delegate() {
+ return delegate;
+ }
+
+ @SuppressWarnings("unchecked") // value could not get in if not a T
+ private <T extends B> T trustedGet(TypeToken<T> type) {
+ return (T) delegate.get(type);
+ }
+}
diff --git a/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java b/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java
new file mode 100644
index 0000000..5f1249d
--- /dev/null
+++ b/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 The Guava 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 com.google.common.reflect;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ForwardingMap;
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * A mutable type-to-instance map.
+ * See also {@link ImmutableTypeToInstanceMap}.
+ *
+ * @author Ben Yu
+ * @since 13.0
+ */
+@Beta
+public final class MutableTypeToInstanceMap<B> extends ForwardingMap<TypeToken<? extends B>, B>
+ implements TypeToInstanceMap<B> {
+
+ private final Map<TypeToken<? extends B>, B> backingMap = Maps.newHashMap();
+
+ @Nullable
+ @Override
+ public <T extends B> T getInstance(Class<T> type) {
+ return trustedGet(TypeToken.of(type));
+ }
+
+ @Nullable
+ @Override
+ public <T extends B> T putInstance(Class<T> type, @Nullable T value) {
+ return trustedPut(TypeToken.of(type), value);
+ }
+
+ @Nullable
+ @Override
+ public <T extends B> T getInstance(TypeToken<T> type) {
+ return trustedGet(type.rejectTypeVariables());
+ }
+
+ @Nullable
+ @Override
+ public <T extends B> T putInstance(TypeToken<T> type, @Nullable T value) {
+ return trustedPut(type.rejectTypeVariables(), value);
+ }
+
+ /** Not supported. Use {@link #putInstance} instead. */
+ @Override public B put(TypeToken<? extends B> key, B value) {
+ throw new UnsupportedOperationException("Please use putInstance() instead.");
+ }
+
+ /** Not supported. Use {@link #putInstance} instead. */
+ @Override public void putAll(Map<? extends TypeToken<? extends B>, ? extends B> map) {
+ throw new UnsupportedOperationException("Please use putInstance() instead.");
+ }
+
+ @Override protected Map<TypeToken<? extends B>, B> delegate() {
+ return backingMap;
+ }
+
+ @SuppressWarnings("unchecked") // value could not get in if not a T
+ @Nullable
+ private <T extends B> T trustedPut(TypeToken<T> type, @Nullable T value) {
+ return (T) backingMap.put(type, value);
+ }
+
+ @SuppressWarnings("unchecked") // value could not get in if not a T
+ @Nullable
+ private <T extends B> T trustedGet(TypeToken<T> type) {
+ return (T) backingMap.get(type);
+ }
+}
diff --git a/guava/src/com/google/common/reflect/Reflection.java b/guava/src/com/google/common/reflect/Reflection.java
new file mode 100644
index 0000000..6b25f01
--- /dev/null
+++ b/guava/src/com/google/common/reflect/Reflection.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2005 The Guava 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 com.google.common.reflect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+
+/**
+ * Static utilities relating to Java reflection.
+ *
+ * @since 12.0
+ */
+@Beta
+public final class Reflection {
+
+ /**
+ * Returns the package name of {@code cls} according to the Java Language Specification (section
+ * 6.7). Unlike {@link Class#getPackage}, this method only parses the class name, without
+ * attempting to define the {@link Package} and hence load files.
+ */
+ public static String getPackageName(Class<?> cls) {
+ return getPackageName(cls.getName());
+ }
+
+ /**
+ * Returns the package name of {@code classFullName} according to the Java Language Specification
+ * (section 6.7). Unlike {@link Class#getPackage}, this method only parses the class name, without
+ * attempting to define the {@link Package} and hence load files.
+ */
+ public static String getPackageName(String classFullName) {
+ int lastDot = classFullName.lastIndexOf('.');
+ if (lastDot < 0) {
+ return "";
+ } else {
+ return classFullName.substring(0, lastDot);
+ }
+ }
+
+ /**
+ * Ensures that the given classes are initialized, as described in
+ * <a href="http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4.2">
+ * JLS Section 12.4.2</a>.
+ *
+ * <p>WARNING: Normally it's a smell if a class needs to be explicitly initialized, because static
+ * state hurts system maintainability and testability. In cases when you have no choice while
+ * inter-operating with a legacy framework, this method helps to keep the code less ugly.
+ *
+ * @throws ExceptionInInitializerError if an exception is thrown during
+ * initialization of a class
+ */
+ public static void initialize(Class<?>... classes) {
+ for (Class<?> clazz : classes) {
+ try {
+ Class.forName(clazz.getName(), true, clazz.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ /**
+ * Returns a proxy instance that implements {@code interfaceType} by
+ * dispatching method invocations to {@code handler}. The class loader of
+ * {@code interfaceType} will be used to define the proxy class. To implement
+ * multiple interfaces or specify a class loader, use
+ * {@link Proxy#newProxyInstance}.
+ *
+ * @throws IllegalArgumentException if {@code interfaceType} does not specify
+ * the type of a Java interface
+ */
+ public static <T> T newProxy(
+ Class<T> interfaceType, InvocationHandler handler) {
+ checkNotNull(interfaceType);
+ checkNotNull(handler);
+ checkArgument(interfaceType.isInterface());
+ Object object = Proxy.newProxyInstance(
+ interfaceType.getClassLoader(),
+ new Class<?>[] { interfaceType },
+ handler);
+ return interfaceType.cast(object);
+ }
+
+ private Reflection() {}
+}
diff --git a/guava/src/com/google/common/reflect/TypeCapture.java b/guava/src/com/google/common/reflect/TypeCapture.java
new file mode 100644
index 0000000..c686661
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeCapture.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Guava 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 com.google.common.reflect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * Captures the actual type of {@code T}.
+ *
+ * @author Ben Yu
+ */
+abstract class TypeCapture<T> {
+
+ /** Returns the captured type. */
+ final Type capture() {
+ Type superclass = getClass().getGenericSuperclass();
+ checkArgument(superclass instanceof ParameterizedType,
+ "%s isn't parameterized", superclass);
+ return ((ParameterizedType) superclass).getActualTypeArguments()[0];
+ }
+}
diff --git a/guava/src/com/google/common/reflect/TypeParameter.java b/guava/src/com/google/common/reflect/TypeParameter.java
new file mode 100644
index 0000000..a6a46bc
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeParameter.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011 The Guava 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 com.google.common.reflect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+
+/**
+ * Captures a free type variable that can be used in {@link TypeToken#where}.
+ * For example: <pre> {@code
+ *
+ * static <T> TypeToken<List<T>> listOf(Class<T> elementType) {
+ * return new TypeToken<List<T>>() {}
+ * .where(new TypeParameter<T>() {}, elementType);
+ * }
+ * }</pre>
+ *
+ * @author Ben Yu
+ * @since 12.0
+ */
+@Beta
+public abstract class TypeParameter<T> extends TypeCapture<T> {
+
+ final TypeVariable<?> typeVariable;
+
+ private TypeParameter(TypeVariable<?> typeVariable) {
+ this.typeVariable = checkNotNull(typeVariable);
+ }
+
+ protected TypeParameter() {
+ Type type = capture();
+ checkArgument(type instanceof TypeVariable, "%s should be a type variable.", type);
+ this.typeVariable = (TypeVariable<?>) type;
+ }
+
+ @Override public final int hashCode() {
+ return typeVariable.hashCode();
+ }
+
+ @Override public final boolean equals(Object o) {
+ if (o instanceof TypeParameter) {
+ TypeParameter<?> that = (TypeParameter<?>) o;
+ return typeVariable.equals(that.typeVariable);
+ }
+ return false;
+ }
+
+ @Override public String toString() {
+ return typeVariable.toString();
+ }
+}
diff --git a/guava/src/com/google/common/reflect/TypeResolver.java b/guava/src/com/google/common/reflect/TypeResolver.java
new file mode 100644
index 0000000..0c42ef5
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeResolver.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2009 The Guava 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 com.google.common.reflect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.annotation.Nullable;
+
+/**
+ * An object of this class encapsulates type mappings from type variables. Mappings are established
+ * with {@link #where} and types are resolved using {@link #resolveType}.
+ *
+ * <p>Note that usually type mappings are already implied by the static type hierarchy (for example,
+ * the {@code E} type variable declared by class {@code List} naturally maps to {@code String} in
+ * the context of {@code class MyStringList implements List<String>}. In such case, prefer to use
+ * {@link TypeToken#resolveType} since it's simpler and more type safe. This class should only be
+ * used when the type mapping isn't implied by the static type hierarchy, but provided through other
+ * means such as an annotation or external configuration file.
+ *
+ * @author Ben Yu
+ */
+class TypeResolver {
+
+ private final ImmutableMap<TypeVariable<?>, Type> typeTable;
+
+ public TypeResolver() {
+ this.typeTable = ImmutableMap.of();
+ }
+
+ private TypeResolver(ImmutableMap<TypeVariable<?>, Type> typeTable) {
+ this.typeTable = typeTable;
+ }
+
+ static TypeResolver accordingTo(Type type) {
+ return new TypeResolver().where(TypeMappingIntrospector.getTypeMappings(type));
+ }
+
+ /**
+ * Returns a new {@code TypeResolver} with type variables in {@code formal} mapping to types in
+ * {@code actual}.
+ *
+ * <p>For example, if {@code formal} is a {@code TypeVariable T}, and {@code actual} is {@code
+ * String.class}, then {@code new TypeResolver().where(formal, actual)} will {@linkplain
+ * #resolveType resolve} {@code ParameterizedType List<T>} to {@code List<String>}, and resolve
+ * {@code Map<T, Something>} to {@code Map<String, Something>} etc. Similarly, {@code formal} and
+ * {@code actual} can be {@code Map<K, V>} and {@code Map<String, Integer>} respectively, or they
+ * can be {@code E[]} and {@code String[]} respectively, or even any arbitrary combination
+ * thereof.
+ *
+ * @param formal The type whose type variables or itself is mapped to other type(s). It's almost
+ * always a bug if {@code formal} isn't a type variable and contains no type variable. Make
+ * sure you are passing the two parameters in the right order.
+ * @param actual The type that the formal type variable(s) are mapped to. It can be or contain yet
+ * other type variables, in which case these type variables will be further resolved if
+ * corresponding mappings exist in the current {@code TypeResolver} instance.
+ */
+ public final TypeResolver where(Type formal, Type actual) {
+ Map<TypeVariable<?>, Type> mappings = Maps.newHashMap();
+ populateTypeMappings(mappings, formal, actual);
+ return where(mappings);
+ }
+
+ /** Returns a new {@code TypeResolver} with {@code variable} mapping to {@code type}. */
+ final TypeResolver where(Map<? extends TypeVariable<?>, ? extends Type> mappings) {
+ ImmutableMap.Builder<TypeVariable<?>, Type> builder = ImmutableMap.builder();
+ builder.putAll(typeTable);
+ for (Map.Entry<? extends TypeVariable<?>, ? extends Type> mapping : mappings.entrySet()) {
+ TypeVariable<?> variable = mapping.getKey();
+ Type type = mapping.getValue();
+ checkArgument(!variable.equals(type), "Type variable %s bound to itself", variable);
+ builder.put(variable, type);
+ }
+ return new TypeResolver(builder.build());
+ }
+
+ private static void populateTypeMappings(
+ Map<TypeVariable<?>, Type> mappings, Type from, Type to) {
+ if (from.equals(to)) {
+ return;
+ }
+ if (from instanceof TypeVariable) {
+ mappings.put((TypeVariable<?>) from, to);
+ } else if (from instanceof GenericArrayType) {
+ populateTypeMappings(mappings,
+ ((GenericArrayType) from).getGenericComponentType(),
+ checkNonNullArgument(Types.getComponentType(to), "%s is not an array type.", to));
+ } else if (from instanceof ParameterizedType) {
+ ParameterizedType fromParameterizedType = (ParameterizedType) from;
+ ParameterizedType toParameterizedType = expectArgument(ParameterizedType.class, to);
+ checkArgument(fromParameterizedType.getRawType().equals(toParameterizedType.getRawType()),
+ "Inconsistent raw type: %s vs. %s", from, to);
+ Type[] fromArgs = fromParameterizedType.getActualTypeArguments();
+ Type[] toArgs = toParameterizedType.getActualTypeArguments();
+ checkArgument(fromArgs.length == toArgs.length);
+ for (int i = 0; i < fromArgs.length; i++) {
+ populateTypeMappings(mappings, fromArgs[i], toArgs[i]);
+ }
+ } else if (from instanceof WildcardType) {
+ WildcardType fromWildcardType = (WildcardType) from;
+ WildcardType toWildcardType = expectArgument(WildcardType.class, to);
+ Type[] fromUpperBounds = fromWildcardType.getUpperBounds();
+ Type[] toUpperBounds = toWildcardType.getUpperBounds();
+ Type[] fromLowerBounds = fromWildcardType.getLowerBounds();
+ Type[] toLowerBounds = toWildcardType.getLowerBounds();
+ checkArgument(
+ fromUpperBounds.length == toUpperBounds.length
+ && fromLowerBounds.length == toLowerBounds.length,
+ "Incompatible type: %s vs. %s", from, to);
+ for (int i = 0; i < fromUpperBounds.length; i++) {
+ populateTypeMappings(mappings, fromUpperBounds[i], toUpperBounds[i]);
+ }
+ for (int i = 0; i < fromLowerBounds.length; i++) {
+ populateTypeMappings(mappings, fromLowerBounds[i], toLowerBounds[i]);
+ }
+ } else {
+ throw new IllegalArgumentException("No type mapping from " + from);
+ }
+ }
+
+ /**
+ * Resolves all type variables in {@code type} and all downstream types and
+ * returns a corresponding type with type variables resolved.
+ */
+ public final Type resolveType(Type type) {
+ if (type instanceof TypeVariable) {
+ return resolveTypeVariable((TypeVariable<?>) type);
+ } else if (type instanceof ParameterizedType) {
+ return resolveParameterizedType((ParameterizedType) type);
+ } else if (type instanceof GenericArrayType) {
+ return resolveGenericArrayType((GenericArrayType) type);
+ } else if (type instanceof WildcardType) {
+ WildcardType wildcardType = (WildcardType) type;
+ return new Types.WildcardTypeImpl(
+ resolveTypes(wildcardType.getLowerBounds()),
+ resolveTypes(wildcardType.getUpperBounds()));
+ } else {
+ // if Class<?>, no resolution needed, we are done.
+ return type;
+ }
+ }
+
+ private Type[] resolveTypes(Type[] types) {
+ Type[] result = new Type[types.length];
+ for (int i = 0; i < types.length; i++) {
+ result[i] = resolveType(types[i]);
+ }
+ return result;
+ }
+
+ private Type resolveGenericArrayType(GenericArrayType type) {
+ Type componentType = resolveType(type.getGenericComponentType());
+ return Types.newArrayType(componentType);
+ }
+
+ private Type resolveTypeVariable(final TypeVariable<?> var) {
+ final TypeResolver unguarded = this;
+ TypeResolver guarded = new TypeResolver(typeTable) {
+ @Override Type resolveTypeVariable(
+ TypeVariable<?> intermediateVar, TypeResolver guardedResolver) {
+ if (intermediateVar.getGenericDeclaration().equals(var.getGenericDeclaration())) {
+ return intermediateVar;
+ }
+ return unguarded.resolveTypeVariable(intermediateVar, guardedResolver);
+ }
+ };
+ return resolveTypeVariable(var, guarded);
+ }
+
+ /**
+ * Resolves {@code var} using the encapsulated type mapping. If it maps to yet another
+ * non-reified type, {@code guardedResolver} is used to do further resolution, which doesn't try
+ * to resolve any type variable on generic declarations that are already being resolved.
+ */
+ Type resolveTypeVariable(TypeVariable<?> var, TypeResolver guardedResolver) {
+ Type type = typeTable.get(var);
+ if (type == null) {
+ Type[] bounds = var.getBounds();
+ if (bounds.length == 0) {
+ return var;
+ }
+ return Types.newTypeVariable(
+ var.getGenericDeclaration(),
+ var.getName(),
+ guardedResolver.resolveTypes(bounds));
+ }
+ return guardedResolver.resolveType(type); // in case the type is yet another type variable.
+ }
+
+ private ParameterizedType resolveParameterizedType(ParameterizedType type) {
+ Type owner = type.getOwnerType();
+ Type resolvedOwner = (owner == null) ? null : resolveType(owner);
+ Type resolvedRawType = resolveType(type.getRawType());
+
+ Type[] vars = type.getActualTypeArguments();
+ Type[] resolvedArgs = new Type[vars.length];
+ for (int i = 0; i < vars.length; i++) {
+ resolvedArgs[i] = resolveType(vars[i]);
+ }
+ return Types.newParameterizedTypeWithOwner(
+ resolvedOwner, (Class<?>) resolvedRawType, resolvedArgs);
+ }
+
+ private static <T> T checkNonNullArgument(T arg, String format, Object... messageParams) {
+ checkArgument(arg != null, format, messageParams);
+ return arg;
+ }
+
+ private static <T> T expectArgument(Class<T> type, Object arg) {
+ try {
+ return type.cast(arg);
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException(arg + " is not a " + type.getSimpleName());
+ }
+ }
+
+ private static final class TypeMappingIntrospector {
+
+ private static final WildcardCapturer wildcardCapturer = new WildcardCapturer();
+
+ private final Map<TypeVariable<?>, Type> mappings = Maps.newHashMap();
+ private final Set<Type> introspectedTypes = Sets.newHashSet();
+
+ /**
+ * Returns type mappings using type parameters and type arguments found in
+ * the generic superclass and the super interfaces of {@code contextClass}.
+ */
+ static ImmutableMap<TypeVariable<?>, Type> getTypeMappings(
+ Type contextType) {
+ TypeMappingIntrospector introspector = new TypeMappingIntrospector();
+ introspector.introspect(wildcardCapturer.capture(contextType));
+ return ImmutableMap.copyOf(introspector.mappings);
+ }
+
+ private void introspect(Type type) {
+ if (!introspectedTypes.add(type)) {
+ return;
+ }
+ if (type instanceof ParameterizedType) {
+ introspectParameterizedType((ParameterizedType) type);
+ } else if (type instanceof Class) {
+ introspectClass((Class<?>) type);
+ } else if (type instanceof TypeVariable) {
+ for (Type bound : ((TypeVariable<?>) type).getBounds()) {
+ introspect(bound);
+ }
+ } else if (type instanceof WildcardType) {
+ for (Type bound : ((WildcardType) type).getUpperBounds()) {
+ introspect(bound);
+ }
+ }
+ }
+
+ private void introspectClass(Class<?> clazz) {
+ introspect(clazz.getGenericSuperclass());
+ for (Type interfaceType : clazz.getGenericInterfaces()) {
+ introspect(interfaceType);
+ }
+ }
+
+ private void introspectParameterizedType(
+ ParameterizedType parameterizedType) {
+ Class<?> rawClass = (Class<?>) parameterizedType.getRawType();
+ TypeVariable<?>[] vars = rawClass.getTypeParameters();
+ Type[] typeArgs = parameterizedType.getActualTypeArguments();
+ checkState(vars.length == typeArgs.length);
+ for (int i = 0; i < vars.length; i++) {
+ map(vars[i], typeArgs[i]);
+ }
+ introspectClass(rawClass);
+ introspect(parameterizedType.getOwnerType());
+ }
+
+ private void map(final TypeVariable<?> var, final Type arg) {
+ if (mappings.containsKey(var)) {
+ // Mapping already established
+ // This is possible when following both superClass -> enclosingClass
+ // and enclosingclass -> superClass paths.
+ // Since we follow the path of superclass first, enclosing second,
+ // superclass mapping should take precedence.
+ return;
+ }
+ // First, check whether var -> arg forms a cycle
+ for (Type t = arg; t != null; t = mappings.get(t)) {
+ if (var.equals(t)) {
+ // cycle detected, remove the entire cycle from the mapping so that
+ // each type variable resolves deterministically to itself.
+ // Otherwise, a F -> T cycle will end up resolving both F and T
+ // nondeterministically to either F or T.
+ for (Type x = arg; x != null; x = mappings.remove(x)) {}
+ return;
+ }
+ }
+ mappings.put(var, arg);
+ }
+ }
+
+ // This is needed when resolving types against a context with wildcards
+ // For example:
+ // class Holder<T> {
+ // void set(T data) {...}
+ // }
+ // Holder<List<?>> should *not* resolve the set() method to set(List<?> data).
+ // Instead, it should create a capture of the wildcard so that set() rejects any List<T>.
+ private static final class WildcardCapturer {
+
+ private final AtomicInteger id = new AtomicInteger();
+
+ Type capture(Type type) {
+ checkNotNull(type);
+ if (type instanceof Class) {
+ return type;
+ }
+ if (type instanceof TypeVariable) {
+ return type;
+ }
+ if (type instanceof GenericArrayType) {
+ GenericArrayType arrayType = (GenericArrayType) type;
+ return Types.newArrayType(capture(arrayType.getGenericComponentType()));
+ }
+ if (type instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType) type;
+ return Types.newParameterizedTypeWithOwner(
+ captureNullable(parameterizedType.getOwnerType()),
+ (Class<?>) parameterizedType.getRawType(),
+ capture(parameterizedType.getActualTypeArguments()));
+ }
+ if (type instanceof WildcardType) {
+ WildcardType wildcardType = (WildcardType) type;
+ Type[] lowerBounds = wildcardType.getLowerBounds();
+ if (lowerBounds.length == 0) { // ? extends something changes to capture-of
+ Type[] upperBounds = wildcardType.getUpperBounds();
+ String name = "capture#" + id.incrementAndGet() + "-of ? extends "
+ + Joiner.on('&').join(upperBounds);
+ return Types.newTypeVariable(
+ WildcardCapturer.class, name, wildcardType.getUpperBounds());
+ } else {
+ // TODO(benyu): handle ? super T somehow.
+ return type;
+ }
+ }
+ throw new AssertionError("must have been one of the known types");
+ }
+
+ private Type captureNullable(@Nullable Type type) {
+ if (type == null) {
+ return null;
+ }
+ return capture(type);
+ }
+
+ private Type[] capture(Type[] types) {
+ Type[] result = new Type[types.length];
+ for (int i = 0; i < types.length; i++) {
+ result[i] = capture(types[i]);
+ }
+ return result;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/reflect/TypeToInstanceMap.java b/guava/src/com/google/common/reflect/TypeToInstanceMap.java
new file mode 100644
index 0000000..3b00820
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeToInstanceMap.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2012 The Guava 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 com.google.common.reflect;
+
+import com.google.common.annotations.Beta;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * A map, each entry of which maps a {@link TypeToken} to an instance of that type.
+ * In addition to implementing {@code Map}, the additional type-safe operations
+ * {@link #putInstance} and {@link #getInstance} are available.
+ *
+ * <p>Generally, implementations don't support {@link #put} and {@link #putAll}
+ * because there is no way to check an object at runtime to be an instance of a
+ * {@link TypeToken}. Instead, caller should use the type safe {@link #putInstance}.
+ *
+ * <p>Also, if caller suppresses unchecked warnings and passes in an {@code Iterable<String>}
+ * for type {@code Iterable<Integer>}, the map won't be able to detect and throw type error.
+ *
+ * <p>Like any other {@code Map<Class, Object>}, this map may contain entries
+ * for primitive types, and a primitive type and its corresponding wrapper type
+ * may map to different values.
+ *
+ * @param <B> the common supertype that all entries must share; often this is
+ * simply {@link Object}
+ *
+ * @author Ben Yu
+ * @since 13.0
+ */
+@Beta
+public interface TypeToInstanceMap<B> extends Map<TypeToken<? extends B>, B> {
+
+ /**
+ * Returns the value the specified class is mapped to, or {@code null} if no
+ * entry for this class is present. This will only return a value that was
+ * bound to this specific class, not a value that may have been bound to a
+ * subtype.
+ *
+ * <p>{@code getInstance(Foo.class)} is equivalent to
+ * {@code getInstance(TypeToken.of(Foo.class))}.
+ */
+ @Nullable
+ <T extends B> T getInstance(Class<T> type);
+
+ /**
+ * Maps the specified class to the specified value. Does <i>not</i> associate
+ * this value with any of the class's supertypes.
+ *
+ * <p>{@code putInstance(Foo.class, foo)} is equivalent to
+ * {@code putInstance(TypeToken.of(Foo.class), foo)}.
+ *
+ * @return the value previously associated with this class (possibly {@code null}),
+ * or {@code null} if there was no previous entry.
+ */
+ @Nullable
+ <T extends B> T putInstance(Class<T> type, @Nullable T value);
+
+ /**
+ * Returns the value the specified type is mapped to, or {@code null} if no
+ * entry for this type is present. This will only return a value that was
+ * bound to this specific type, not a value that may have been bound to a subtype.
+ */
+ @Nullable
+ <T extends B> T getInstance(TypeToken<T> type);
+
+ /**
+ * Maps the specified type to the specified value. Does <i>not</i> associate
+ * this value with any of the type's supertypes.
+ *
+ * @return the value previously associated with this type (possibly {@code null}),
+ * or {@code null} if there was no previous entry.
+ */
+ @Nullable
+ <T extends B> T putInstance(TypeToken<T> type, @Nullable T value);
+}
diff --git a/guava/src/com/google/common/reflect/TypeToken.java b/guava/src/com/google/common/reflect/TypeToken.java
new file mode 100644
index 0000000..08a2440
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeToken.java
@@ -0,0 +1,1086 @@
+/*
+ * Copyright (C) 2006 The Guava 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 com.google.common.reflect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ForwardingSet;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Ordering;
+
+import java.io.Serializable;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A {@link Type} with generics.
+ *
+ * <p>Operations that are otherwise only available in {@link Class} are implemented to support
+ * {@code Type}, for example {@link #isAssignableFrom}, {@link #isArray} and {@link
+ * #getComponentType}. It also provides additional utilities such as {@link #getTypes} and {@link
+ * #resolveType} etc.
+ *
+ * <p>There are three ways to get a {@code TypeToken} instance: <ul>
+ * <li>Wrap a {@code Type} obtained via reflection. For example: {@code
+ * TypeToken.of(method.getGenericReturnType())}.
+ * <li>Capture a generic type with a (usually anonymous) subclass. For example: <pre> {@code
+ *
+ * new TypeToken<List<String>>() {}
+ * }</pre>
+ * Note that it's critical that the actual type argument is carried by a subclass.
+ * The following code is wrong because it only captures the {@code <T>} type variable
+ * of the {@code listType()} method signature; while {@code <String>} is lost in erasure:
+ * <pre> {@code
+ *
+ * class Util {
+ * static <T> TypeToken<List<T>> listType() {
+ * return new TypeToken<List<T>>() {};
+ * }
+ * }
+ *
+ * TypeToken<List<String>> stringListType = Util.<String>listType();
+ * }</pre>
+ * <li>Capture a generic type with a (usually anonymous) subclass and resolve it against
+ * a context class that knows what the type parameters are. For example: <pre> {@code
+ * abstract class IKnowMyType<T> {
+ * TypeToken<T> type = new TypeToken<T>(getClass()) {};
+ * }
+ * new IKnowMyType<String>() {}.type => String
+ * }</pre>
+ * </ul>
+ *
+ * <p>{@code TypeToken} is serializable when no type variable is contained in the type.
+ *
+ * <p>Note to Guice users: {@code} TypeToken is similar to Guice's {@code TypeLiteral} class,
+ * but with one important difference: it supports non-reified types such as {@code T},
+ * {@code List<T>} or even {@code List<? extends Number>}; while TypeLiteral does not.
+ * TypeToken is also serializable and offers numerous additional utility methods.
+ *
+ * @author Bob Lee
+ * @author Sven Mawson
+ * @author Ben Yu
+ * @since 12.0
+ */
+@Beta
+@SuppressWarnings("serial") // SimpleTypeToken is the serialized form.
+public abstract class TypeToken<T> extends TypeCapture<T> implements Serializable {
+
+ private final Type runtimeType;
+
+ /** Resolver for resolving types with {@link #runtimeType} as context. */
+ private transient TypeResolver typeResolver;
+
+ /**
+ * Constructs a new type token of {@code T}.
+ *
+ * <p>Clients create an empty anonymous subclass. Doing so embeds the type
+ * parameter in the anonymous class's type hierarchy so we can reconstitute
+ * it at runtime despite erasure.
+ *
+ * <p>For example: <pre> {@code
+ *
+ * TypeToken<List<String>> t = new TypeToken<List<String>>() {};
+ * }</pre>
+ */
+ protected TypeToken() {
+ this.runtimeType = capture();
+ checkState(!(runtimeType instanceof TypeVariable),
+ "Cannot construct a TypeToken for a type variable.\n" +
+ "You probably meant to call new TypeToken<%s>(getClass()) " +
+ "that can resolve the type variable for you.\n" +
+ "If you do need to create a TypeToken of a type variable, " +
+ "please use TypeToken.of() instead.", runtimeType);
+ }
+
+ /**
+ * Constructs a new type token of {@code T} while resolving free type variables in the context of
+ * {@code declaringClass}.
+ *
+ * <p>Clients create an empty anonymous subclass. Doing so embeds the type
+ * parameter in the anonymous class's type hierarchy so we can reconstitute
+ * it at runtime despite erasure.
+ *
+ * <p>For example: <pre> {@code
+ *
+ * abstract class IKnowMyType<T> {
+ * TypeToken<T> getMyType() {
+ * return new TypeToken<T>(getClass()) {};
+ * }
+ * }
+ *
+ * new IKnowMyType<String>() {}.getMyType() => String
+ * }</pre>
+ */
+ protected TypeToken(Class<?> declaringClass) {
+ Type captured = super.capture();
+ if (captured instanceof Class) {
+ this.runtimeType = captured;
+ } else {
+ this.runtimeType = of(declaringClass).resolveType(captured).runtimeType;
+ }
+ }
+
+ private TypeToken(Type type) {
+ this.runtimeType = checkNotNull(type);
+ }
+
+ /** Returns an instance of type token that wraps {@code type}. */
+ public static <T> TypeToken<T> of(Class<T> type) {
+ return new SimpleTypeToken<T>(type);
+ }
+
+ /** Returns an instance of type token that wraps {@code type}. */
+ public static TypeToken<?> of(Type type) {
+ return new SimpleTypeToken<Object>(type);
+ }
+
+ /**
+ * Returns the raw type of {@code T}. Formally speaking, if {@code T} is returned by
+ * {@link java.lang.reflect.Method#getGenericReturnType}, the raw type is what's returned by
+ * {@link java.lang.reflect.Method#getReturnType} of the same method object. Specifically:
+ * <ul>
+ * <li>If {@code T} is a {@code Class} itself, {@code T} itself is returned.
+ * <li>If {@code T} is a {@link ParameterizedType}, the raw type of the parameterized type is
+ * returned.
+ * <li>If {@code T} is a {@link GenericArrayType}, the returned type is the corresponding array
+ * class. For example: {@code List<Integer>[] => List[]}.
+ * <li>If {@code T} is a type variable or a wildcard type, the raw type of the first upper bound
+ * is returned. For example: {@code <X extends Foo> => Foo}.
+ * </ul>
+ */
+ public final Class<? super T> getRawType() {
+ Class<?> rawType = getRawType(runtimeType);
+ @SuppressWarnings("unchecked") // raw type is |T|
+ Class<? super T> result = (Class<? super T>) rawType;
+ return result;
+ }
+
+ /**
+ * Returns the raw type of the class or parameterized type; if {@code T} is type variable or
+ * wildcard type, the raw types of all its upper bounds are returned.
+ */
+ private ImmutableSet<Class<? super T>> getImmediateRawTypes() {
+ // Cast from ImmutableSet<Class<?>> to ImmutableSet<Class<? super T>>
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ ImmutableSet<Class<? super T>> result = (ImmutableSet) getRawTypes(runtimeType);
+ return result;
+ }
+
+ /** Returns the represented type. */
+ public final Type getType() {
+ return runtimeType;
+ }
+
+ /**
+ * Returns a new {@code TypeToken} where type variables represented by {@code typeParam}
+ * are substituted by {@code typeArg}. For example, it can be used to construct
+ * {@code Map<K, V>} for any {@code K} and {@code V} type: <pre> {@code
+ *
+ * static <K, V> TypeToken<Map<K, V>> mapOf(
+ * TypeToken<K> keyType, TypeToken<V> valueType) {
+ * return new TypeToken<Map<K, V>>() {}
+ * .where(new TypeParameter<K>() {}, keyType)
+ * .where(new TypeParameter<V>() {}, valueType);
+ * }
+ * }</pre>
+ *
+ * @param <X> The parameter type
+ * @param typeParam the parameter type variable
+ * @param typeArg the actual type to substitute
+ */
+ public final <X> TypeToken<T> where(TypeParameter<X> typeParam, TypeToken<X> typeArg) {
+ TypeResolver resolver = new TypeResolver()
+ .where(ImmutableMap.of(typeParam.typeVariable, typeArg.runtimeType));
+ // If there's any type error, we'd report now rather than later.
+ return new SimpleTypeToken<T>(resolver.resolveType(runtimeType));
+ }
+
+ /**
+ * Returns a new {@code TypeToken} where type variables represented by {@code typeParam}
+ * are substituted by {@code typeArg}. For example, it can be used to construct
+ * {@code Map<K, V>} for any {@code K} and {@code V} type: <pre> {@code
+ *
+ * static <K, V> TypeToken<Map<K, V>> mapOf(
+ * Class<K> keyType, Class<V> valueType) {
+ * return new TypeToken<Map<K, V>>() {}
+ * .where(new TypeParameter<K>() {}, keyType)
+ * .where(new TypeParameter<V>() {}, valueType);
+ * }
+ * }</pre>
+ *
+ * @param <X> The parameter type
+ * @param typeParam the parameter type variable
+ * @param typeArg the actual type to substitute
+ */
+ public final <X> TypeToken<T> where(TypeParameter<X> typeParam, Class<X> typeArg) {
+ return where(typeParam, of(typeArg));
+ }
+
+ /**
+ * Resolves the given {@code type} against the type context represented by this type.
+ * For example: <pre> {@code
+ *
+ * new TypeToken<List<String>>() {}.resolveType(
+ * List.class.getMethod("get", int.class).getGenericReturnType())
+ * => String.class
+ * }</pre>
+ */
+ public final TypeToken<?> resolveType(Type type) {
+ checkNotNull(type);
+ TypeResolver resolver = typeResolver;
+ if (resolver == null) {
+ resolver = (typeResolver = TypeResolver.accordingTo(runtimeType));
+ }
+ return of(resolver.resolveType(type));
+ }
+
+ private TypeToken<?> resolveSupertype(Type type) {
+ TypeToken<?> supertype = resolveType(type);
+ // super types' type mapping is a subset of type mapping of this type.
+ supertype.typeResolver = typeResolver;
+ return supertype;
+ }
+
+ /**
+ * Returns the generic superclass of this type or {@code null} if the type represents
+ * {@link Object} or an interface. This method is similar but different from {@link
+ * Class#getGenericSuperclass}. For example, {@code
+ * new TypeToken<StringArrayList>() {}.getGenericSuperclass()} will return {@code
+ * new TypeToken<ArrayList<String>>() {}}; while {@code
+ * StringArrayList.class.getGenericSuperclass()} will return {@code ArrayList<E>}, where {@code E}
+ * is the type variable declared by class {@code ArrayList}.
+ *
+ * <p>If this type is a type variable or wildcard, its first upper bound is examined and returned
+ * if the bound is a class or extends from a class. This means that the returned type could be a
+ * type variable too.
+ */
+ @Nullable
+ final TypeToken<? super T> getGenericSuperclass() {
+ if (runtimeType instanceof TypeVariable) {
+ // First bound is always the super class, if one exists.
+ return boundAsSuperclass(((TypeVariable<?>) runtimeType).getBounds()[0]);
+ }
+ if (runtimeType instanceof WildcardType) {
+ // wildcard has one and only one upper bound.
+ return boundAsSuperclass(((WildcardType) runtimeType).getUpperBounds()[0]);
+ }
+ Type superclass = getRawType().getGenericSuperclass();
+ if (superclass == null) {
+ return null;
+ }
+ @SuppressWarnings("unchecked") // super class of T
+ TypeToken<? super T> superToken = (TypeToken<? super T>) resolveSupertype(superclass);
+ return superToken;
+ }
+
+ @Nullable private TypeToken<? super T> boundAsSuperclass(Type bound) {
+ TypeToken<?> token = of(bound);
+ if (token.getRawType().isInterface()) {
+ return null;
+ }
+ @SuppressWarnings("unchecked") // only upper bound of T is passed in.
+ TypeToken<? super T> superclass = (TypeToken<? super T>) token;
+ return superclass;
+ }
+
+ /**
+ * Returns the generic interfaces that this type directly {@code implements}. This method is
+ * similar but different from {@link Class#getGenericInterfaces()}. For example, {@code
+ * new TypeToken<List<String>>() {}.getGenericInterfaces()} will return a list that contains
+ * {@code new TypeToken<Iterable<String>>() {}}; while {@code List.class.getGenericInterfaces()}
+ * will return an array that contains {@code Iterable<T>}, where the {@code T} is the type
+ * variable declared by interface {@code Iterable}.
+ *
+ * <p>If this type is a type variable or wildcard, its upper bounds are examined and those that
+ * are either an interface or upper-bounded only by interfaces are returned. This means that the
+ * returned types could include type variables too.
+ */
+ final ImmutableList<TypeToken<? super T>> getGenericInterfaces() {
+ if (runtimeType instanceof TypeVariable) {
+ return boundsAsInterfaces(((TypeVariable<?>) runtimeType).getBounds());
+ }
+ if (runtimeType instanceof WildcardType) {
+ return boundsAsInterfaces(((WildcardType) runtimeType).getUpperBounds());
+ }
+ ImmutableList.Builder<TypeToken<? super T>> builder = ImmutableList.builder();
+ for (Type interfaceType : getRawType().getGenericInterfaces()) {
+ @SuppressWarnings("unchecked") // interface of T
+ TypeToken<? super T> resolvedInterface = (TypeToken<? super T>)
+ resolveSupertype(interfaceType);
+ builder.add(resolvedInterface);
+ }
+ return builder.build();
+ }
+
+ private ImmutableList<TypeToken<? super T>> boundsAsInterfaces(Type[] bounds) {
+ ImmutableList.Builder<TypeToken<? super T>> builder = ImmutableList.builder();
+ for (Type bound : bounds) {
+ @SuppressWarnings("unchecked") // upper bound of T
+ TypeToken<? super T> boundType = (TypeToken<? super T>) of(bound);
+ if (boundType.getRawType().isInterface()) {
+ builder.add(boundType);
+ }
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns the set of interfaces and classes that this type is or is a subtype of. The returned
+ * types are parameterized with proper type arguments.
+ *
+ * <p>Subtypes are always listed before supertypes. But the reverse is not true. A type isn't
+ * necessarily a subtype of all the types following. Order between types without subtype
+ * relationship is arbitrary and not guaranteed.
+ *
+ * <p>If this type is a type variable or wildcard, upper bounds that are themselves type variables
+ * aren't included (their super interfaces and superclasses are).
+ */
+ public final TypeSet getTypes() {
+ return new TypeSet();
+ }
+
+ /**
+ * Returns the generic form of {@code superclass}. For example, if this is
+ * {@code ArrayList<String>}, {@code Iterable<String>} is returned given the
+ * input {@code Iterable.class}.
+ */
+ public final TypeToken<? super T> getSupertype(Class<? super T> superclass) {
+ checkArgument(superclass.isAssignableFrom(getRawType()),
+ "%s is not a super class of %s", superclass, this);
+ if (runtimeType instanceof TypeVariable) {
+ return getSupertypeFromUpperBounds(superclass, ((TypeVariable<?>) runtimeType).getBounds());
+ }
+ if (runtimeType instanceof WildcardType) {
+ return getSupertypeFromUpperBounds(superclass, ((WildcardType) runtimeType).getUpperBounds());
+ }
+ if (superclass.isArray()) {
+ return getArraySupertype(superclass);
+ }
+ @SuppressWarnings("unchecked") // resolved supertype
+ TypeToken<? super T> supertype = (TypeToken<? super T>)
+ resolveSupertype(toGenericType(superclass).runtimeType);
+ return supertype;
+ }
+
+ /**
+ * Returns subtype of {@code this} with {@code subclass} as the raw class.
+ * For example, if this is {@code Iterable<String>} and {@code subclass} is {@code List},
+ * {@code List<String>} is returned.
+ */
+ public final TypeToken<? extends T> getSubtype(Class<?> subclass) {
+ checkArgument(!(runtimeType instanceof TypeVariable),
+ "Cannot get subtype of type variable <%s>", this);
+ if (runtimeType instanceof WildcardType) {
+ return getSubtypeFromLowerBounds(subclass, ((WildcardType) runtimeType).getLowerBounds());
+ }
+ checkArgument(getRawType().isAssignableFrom(subclass),
+ "%s isn't a subclass of %s", subclass, this);
+ // unwrap array type if necessary
+ if (isArray()) {
+ return getArraySubtype(subclass);
+ }
+ @SuppressWarnings("unchecked") // guarded by the isAssignableFrom() statement above
+ TypeToken<? extends T> subtype = (TypeToken<? extends T>)
+ of(resolveTypeArgsForSubclass(subclass));
+ return subtype;
+ }
+
+ /** Returns true if this type is assignable from the given {@code type}. */
+ public final boolean isAssignableFrom(TypeToken<?> type) {
+ return isAssignableFrom(type.runtimeType);
+ }
+
+ /** Check if this type is assignable from the given {@code type}. */
+ public final boolean isAssignableFrom(Type type) {
+ return isAssignable(checkNotNull(type), runtimeType);
+ }
+
+ /**
+ * Returns true if this type is known to be an array type, such as {@code int[]}, {@code T[]},
+ * {@code <? extends Map<String, Integer>[]>} etc.
+ */
+ public final boolean isArray() {
+ return getComponentType() != null;
+ }
+
+ /**
+ * Returns the array component type if this type represents an array ({@code int[]}, {@code T[]},
+ * {@code <? extends Map<String, Integer>[]>} etc.), or else {@code null} is returned.
+ */
+ @Nullable public final TypeToken<?> getComponentType() {
+ Type componentType = Types.getComponentType(runtimeType);
+ if (componentType == null) {
+ return null;
+ }
+ return of(componentType);
+ }
+
+ /**
+ * The set of interfaces and classes that {@code T} is or is a subtype of. {@link Object} is not
+ * included in the set if this type is an interface.
+ */
+ public class TypeSet extends ForwardingSet<TypeToken<? super T>> implements Serializable {
+
+ private transient ImmutableSet<TypeToken<? super T>> types;
+
+ TypeSet() {}
+
+ /** Returns the types that are interfaces implemented by this type. */
+ public TypeSet interfaces() {
+ return new InterfaceSet(this);
+ }
+
+ /** Returns the types that are classes. */
+ public TypeSet classes() {
+ return new ClassSet();
+ }
+
+ @Override protected Set<TypeToken<? super T>> delegate() {
+ ImmutableSet<TypeToken<? super T>> filteredTypes = types;
+ if (filteredTypes == null) {
+ // Java has no way to express ? super T when we parameterize TypeToken vs. Class.
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ ImmutableList<TypeToken<? super T>> collectedTypes = (ImmutableList)
+ TypeCollector.FOR_GENERIC_TYPE.collectTypes(TypeToken.this);
+ return (types = FluentIterable.from(collectedTypes)
+ .filter(TypeFilter.IGNORE_TYPE_VARIABLE_OR_WILDCARD)
+ .toImmutableSet());
+ } else {
+ return filteredTypes;
+ }
+ }
+
+ /** Returns the raw types of the types in this set, in the same order. */
+ public Set<Class<? super T>> rawTypes() {
+ // Java has no way to express ? super T when we parameterize TypeToken vs. Class.
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ ImmutableList<Class<? super T>> collectedTypes = (ImmutableList)
+ TypeCollector.FOR_RAW_TYPE.collectTypes(getImmediateRawTypes());
+ return ImmutableSet.copyOf(collectedTypes);
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private final class InterfaceSet extends TypeSet {
+
+ private transient final TypeSet allTypes;
+ private transient ImmutableSet<TypeToken<? super T>> interfaces;
+
+ InterfaceSet(TypeSet allTypes) {
+ this.allTypes = allTypes;
+ }
+
+ @Override protected Set<TypeToken<? super T>> delegate() {
+ ImmutableSet<TypeToken<? super T>> result = interfaces;
+ if (result == null) {
+ return (interfaces = FluentIterable.from(allTypes)
+ .filter(TypeFilter.INTERFACE_ONLY)
+ .toImmutableSet());
+ } else {
+ return result;
+ }
+ }
+
+ @Override public TypeSet interfaces() {
+ return this;
+ }
+
+ @Override public Set<Class<? super T>> rawTypes() {
+ // Java has no way to express ? super T when we parameterize TypeToken vs. Class.
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ ImmutableList<Class<? super T>> collectedTypes = (ImmutableList)
+ TypeCollector.FOR_RAW_TYPE.collectTypes(getImmediateRawTypes());
+ return FluentIterable.from(collectedTypes)
+ .filter(new Predicate<Class<?>>() {
+ @Override public boolean apply(Class<?> type) {
+ return type.isInterface();
+ }
+ })
+ .toImmutableSet();
+ }
+
+ @Override public TypeSet classes() {
+ throw new UnsupportedOperationException("interfaces().classes() not supported.");
+ }
+
+ private Object readResolve() {
+ return getTypes().interfaces();
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private final class ClassSet extends TypeSet {
+
+ private transient ImmutableSet<TypeToken<? super T>> classes;
+
+ @Override protected Set<TypeToken<? super T>> delegate() {
+ ImmutableSet<TypeToken<? super T>> result = classes;
+ if (result == null) {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ ImmutableList<TypeToken<? super T>> collectedTypes = (ImmutableList)
+ TypeCollector.FOR_GENERIC_TYPE.classesOnly().collectTypes(TypeToken.this);
+ return (classes = FluentIterable.from(collectedTypes)
+ .filter(TypeFilter.IGNORE_TYPE_VARIABLE_OR_WILDCARD)
+ .toImmutableSet());
+ } else {
+ return result;
+ }
+ }
+
+ @Override public TypeSet classes() {
+ return this;
+ }
+
+ @Override public Set<Class<? super T>> rawTypes() {
+ // Java has no way to express ? super T when we parameterize TypeToken vs. Class.
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ ImmutableList<Class<? super T>> collectedTypes = (ImmutableList)
+ TypeCollector.FOR_RAW_TYPE.classesOnly().collectTypes(getImmediateRawTypes());
+ return ImmutableSet.copyOf(collectedTypes);
+ }
+
+ @Override public TypeSet interfaces() {
+ throw new UnsupportedOperationException("classes().interfaces() not supported.");
+ }
+
+ private Object readResolve() {
+ return getTypes().classes();
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private enum TypeFilter implements Predicate<TypeToken<?>> {
+
+ IGNORE_TYPE_VARIABLE_OR_WILDCARD {
+ @Override public boolean apply(TypeToken<?> type) {
+ return !(type.runtimeType instanceof TypeVariable
+ || type.runtimeType instanceof WildcardType);
+ }
+ },
+ INTERFACE_ONLY {
+ @Override public boolean apply(TypeToken<?> type) {
+ return type.getRawType().isInterface();
+ }
+ }
+ }
+
+ /**
+ * Returns true if {@code o} is another {@code TypeToken} that represents the same {@link Type}.
+ */
+ @Override public boolean equals(@Nullable Object o) {
+ if (o instanceof TypeToken) {
+ TypeToken<?> that = (TypeToken<?>) o;
+ return runtimeType.equals(that.runtimeType);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return runtimeType.hashCode();
+ }
+
+ @Override public String toString() {
+ return Types.toString(runtimeType);
+ }
+
+ /** Implemented to support serialization of subclasses. */
+ protected Object writeReplace() {
+ // TypeResolver just transforms the type to our own impls that are Serializable
+ // except TypeVariable.
+ return of(new TypeResolver().resolveType(runtimeType));
+ }
+
+ /**
+ * Ensures that this type token doesn't contain type variables, which can cause unchecked type
+ * errors for callers like {@link TypeToInstanceMap}.
+ */
+ final TypeToken<T> rejectTypeVariables() {
+ checkArgument(!Types.containsTypeVariable(runtimeType),
+ "%s contains a type variable and is not safe for the operation");
+ return this;
+ }
+
+ private static boolean isAssignable(Type from, Type to) {
+ if (to.equals(from)) {
+ return true;
+ }
+ if (to instanceof WildcardType) {
+ return isAssignableToWildcardType(from, (WildcardType) to);
+ }
+ // if "from" is type variable, it's assignable if any of its "extends"
+ // bounds is assignable to "to".
+ if (from instanceof TypeVariable) {
+ return isAssignableFromAny(((TypeVariable<?>) from).getBounds(), to);
+ }
+ // if "from" is wildcard, it'a assignable to "to" if any of its "extends"
+ // bounds is assignable to "to".
+ if (from instanceof WildcardType) {
+ return isAssignableFromAny(((WildcardType) from).getUpperBounds(), to);
+ }
+ if (from instanceof GenericArrayType) {
+ return isAssignableFromGenericArrayType((GenericArrayType) from, to);
+ }
+ // Proceed to regular Type assignability check
+ if (to instanceof Class) {
+ return isAssignableToClass(from, (Class<?>) to);
+ } else if (to instanceof ParameterizedType) {
+ return isAssignableToParameterizedType(from, (ParameterizedType) to);
+ } else if (to instanceof GenericArrayType) {
+ return isAssignableToGenericArrayType(from, (GenericArrayType) to);
+ } else { // to instanceof TypeVariable
+ return false;
+ }
+ }
+
+ private static boolean isAssignableFromAny(Type[] fromTypes, Type to) {
+ for (Type from : fromTypes) {
+ if (isAssignable(from, to)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isAssignableToClass(Type from, Class<?> to) {
+ return to.isAssignableFrom(getRawType(from));
+ }
+
+ private static boolean isAssignableToWildcardType(
+ Type from, WildcardType to) {
+ // if "to" is <? extends Foo>, "from" can be:
+ // Foo, SubFoo, <? extends Foo>, <? extends SubFoo>, <T extends Foo> or
+ // <T extends SubFoo>.
+ // if "to" is <? super Foo>, "from" can be:
+ // Foo, SuperFoo, <? super Foo> or <? super SuperFoo>.
+ return isAssignable(from, supertypeBound(to)) && isAssignableBySubtypeBound(from, to);
+ }
+
+ private static boolean isAssignableBySubtypeBound(Type from, WildcardType to) {
+ Type toSubtypeBound = subtypeBound(to);
+ if (toSubtypeBound == null) {
+ return true;
+ }
+ Type fromSubtypeBound = subtypeBound(from);
+ if (fromSubtypeBound == null) {
+ return false;
+ }
+ return isAssignable(toSubtypeBound, fromSubtypeBound);
+ }
+
+ private static boolean isAssignableToParameterizedType(Type from, ParameterizedType to) {
+ Class<?> matchedClass = getRawType(to);
+ if (!matchedClass.isAssignableFrom(getRawType(from))) {
+ return false;
+ }
+ Type[] typeParams = matchedClass.getTypeParameters();
+ Type[] toTypeArgs = to.getActualTypeArguments();
+ TypeToken<?> fromTypeToken = of(from);
+ for (int i = 0; i < typeParams.length; i++) {
+ // If "to" is "List<? extends CharSequence>"
+ // and "from" is StringArrayList,
+ // First step is to figure out StringArrayList "is-a" List<E> and <E> is
+ // String.
+ // typeParams[0] is E and fromTypeToken.get(typeParams[0]) will resolve to
+ // String.
+ // String is then matched against <? extends CharSequence>.
+ Type fromTypeArg = fromTypeToken.resolveType(typeParams[i]).runtimeType;
+ if (!matchTypeArgument(fromTypeArg, toTypeArgs[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean isAssignableToGenericArrayType(Type from, GenericArrayType to) {
+ if (from instanceof Class) {
+ Class<?> fromClass = (Class<?>) from;
+ if (!fromClass.isArray()) {
+ return false;
+ }
+ return isAssignable(fromClass.getComponentType(), to.getGenericComponentType());
+ } else if (from instanceof GenericArrayType) {
+ GenericArrayType fromArrayType = (GenericArrayType) from;
+ return isAssignable(fromArrayType.getGenericComponentType(), to.getGenericComponentType());
+ } else {
+ return false;
+ }
+ }
+
+ private static boolean isAssignableFromGenericArrayType(GenericArrayType from, Type to) {
+ if (to instanceof Class) {
+ Class<?> toClass = (Class<?>) to;
+ if (!toClass.isArray()) {
+ return toClass == Object.class; // any T[] is assignable to Object
+ }
+ return isAssignable(from.getGenericComponentType(), toClass.getComponentType());
+ } else if (to instanceof GenericArrayType) {
+ GenericArrayType toArrayType = (GenericArrayType) to;
+ return isAssignable(from.getGenericComponentType(), toArrayType.getGenericComponentType());
+ } else {
+ return false;
+ }
+ }
+
+ private static boolean matchTypeArgument(Type from, Type to) {
+ if (from.equals(to)) {
+ return true;
+ }
+ if (to instanceof WildcardType) {
+ return isAssignableToWildcardType(from, (WildcardType) to);
+ }
+ return false;
+ }
+
+ private static Type supertypeBound(Type type) {
+ if (type instanceof WildcardType) {
+ return supertypeBound((WildcardType) type);
+ }
+ return type;
+ }
+
+ private static Type supertypeBound(WildcardType type) {
+ Type[] upperBounds = type.getUpperBounds();
+ if (upperBounds.length == 1) {
+ return supertypeBound(upperBounds[0]);
+ } else if (upperBounds.length == 0) {
+ return Object.class;
+ } else {
+ throw new AssertionError(
+ "There should be at most one upper bound for wildcard type: " + type);
+ }
+ }
+
+ @Nullable private static Type subtypeBound(Type type) {
+ if (type instanceof WildcardType) {
+ return subtypeBound((WildcardType) type);
+ } else {
+ return type;
+ }
+ }
+
+ @Nullable private static Type subtypeBound(WildcardType type) {
+ Type[] lowerBounds = type.getLowerBounds();
+ if (lowerBounds.length == 1) {
+ return subtypeBound(lowerBounds[0]);
+ } else if (lowerBounds.length == 0) {
+ return null;
+ } else {
+ throw new AssertionError(
+ "Wildcard should have at most one lower bound: " + type);
+ }
+ }
+
+ @VisibleForTesting static Class<?> getRawType(Type type) {
+ // For wildcard or type variable, the first bound determines the runtime type.
+ return getRawTypes(type).iterator().next();
+ }
+
+ @VisibleForTesting static ImmutableSet<Class<?>> getRawTypes(Type type) {
+ if (type instanceof Class) {
+ return ImmutableSet.<Class<?>>of((Class<?>) type);
+ } else if (type instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType) type;
+ // JDK implementation declares getRawType() to return Class<?>
+ return ImmutableSet.<Class<?>>of((Class<?>) parameterizedType.getRawType());
+ } else if (type instanceof GenericArrayType) {
+ GenericArrayType genericArrayType = (GenericArrayType) type;
+ return ImmutableSet.<Class<?>>of(Types.getArrayClass(
+ getRawType(genericArrayType.getGenericComponentType())));
+ } else if (type instanceof TypeVariable) {
+ return getRawTypes(((TypeVariable<?>) type).getBounds());
+ } else if (type instanceof WildcardType) {
+ return getRawTypes(((WildcardType) type).getUpperBounds());
+ } else {
+ throw new AssertionError(type + " unsupported");
+ }
+ }
+
+ private static ImmutableSet<Class<?>> getRawTypes(Type[] types) {
+ ImmutableSet.Builder<Class<?>> builder = ImmutableSet.builder();
+ for (Type type : types) {
+ builder.addAll(getRawTypes(type));
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns the type token representing the generic type declaration of {@code cls}. For example:
+ * {@code TypeToken.getGenericType(Iterable.class)} returns {@code Iterable<T>}.
+ *
+ * <p>If {@code cls} isn't parameterized and isn't a generic array, the type token of the class is
+ * returned.
+ */
+ @VisibleForTesting static <T> TypeToken<? extends T> toGenericType(Class<T> cls) {
+ if (cls.isArray()) {
+ Type arrayOfGenericType = Types.newArrayType(
+ // If we are passed with int[].class, don't turn it to GenericArrayType
+ toGenericType(cls.getComponentType()).runtimeType);
+ @SuppressWarnings("unchecked") // array is covariant
+ TypeToken<? extends T> result = (TypeToken<? extends T>) of(arrayOfGenericType);
+ return result;
+ }
+ TypeVariable<Class<T>>[] typeParams = cls.getTypeParameters();
+ if (typeParams.length > 0) {
+ @SuppressWarnings("unchecked") // Like, it's Iterable<T> for Iterable.class
+ TypeToken<? extends T> type = (TypeToken<? extends T>)
+ of(Types.newParameterizedType(cls, typeParams));
+ return type;
+ } else {
+ return of(cls);
+ }
+ }
+
+ private TypeToken<? super T> getSupertypeFromUpperBounds(
+ Class<? super T> supertype, Type[] upperBounds) {
+ for (Type upperBound : upperBounds) {
+ @SuppressWarnings("unchecked") // T's upperbound is <? super T>.
+ TypeToken<? super T> bound = (TypeToken<? super T>) of(upperBound);
+ if (of(supertype).isAssignableFrom(bound)) {
+ @SuppressWarnings({"rawtypes", "unchecked"}) // guarded by the isAssignableFrom check.
+ TypeToken<? super T> result = bound.getSupertype((Class) supertype);
+ return result;
+ }
+ }
+ throw new IllegalArgumentException(supertype + " isn't a super type of " + this);
+ }
+
+ private TypeToken<? extends T> getSubtypeFromLowerBounds(Class<?> subclass, Type[] lowerBounds) {
+ for (Type lowerBound : lowerBounds) {
+ @SuppressWarnings("unchecked") // T's lower bound is <? extends T>
+ TypeToken<? extends T> bound = (TypeToken<? extends T>) of(lowerBound);
+ // Java supports only one lowerbound anyway.
+ return bound.getSubtype(subclass);
+ }
+ throw new IllegalArgumentException(subclass + " isn't a subclass of " + this);
+ }
+
+ private TypeToken<? super T> getArraySupertype(Class<? super T> supertype) {
+ // with component type, we have lost generic type information
+ // Use raw type so that compiler allows us to call getSupertype()
+ @SuppressWarnings("rawtypes")
+ TypeToken componentType = checkNotNull(getComponentType(),
+ "%s isn't a super type of %s", supertype, this);
+ // array is covariant. component type is super type, so is the array type.
+ @SuppressWarnings("unchecked") // going from raw type back to generics
+ TypeToken<?> componentSupertype = componentType.getSupertype(supertype.getComponentType());
+ @SuppressWarnings("unchecked") // component type is super type, so is array type.
+ TypeToken<? super T> result = (TypeToken<? super T>)
+ // If we are passed with int[].class, don't turn it to GenericArrayType
+ of(newArrayClassOrGenericArrayType(componentSupertype.runtimeType));
+ return result;
+ }
+
+ private TypeToken<? extends T> getArraySubtype(Class<?> subclass) {
+ // array is covariant. component type is subtype, so is the array type.
+ TypeToken<?> componentSubtype = getComponentType()
+ .getSubtype(subclass.getComponentType());
+ @SuppressWarnings("unchecked") // component type is subtype, so is array type.
+ TypeToken<? extends T> result = (TypeToken<? extends T>)
+ // If we are passed with int[].class, don't turn it to GenericArrayType
+ of(newArrayClassOrGenericArrayType(componentSubtype.runtimeType));
+ return result;
+ }
+
+ private Type resolveTypeArgsForSubclass(Class<?> subclass) {
+ if (runtimeType instanceof Class) {
+ // no resolution needed
+ return subclass;
+ }
+ // class Base<A, B> {}
+ // class Sub<X, Y> extends Base<X, Y> {}
+ // Base<String, Integer>.subtype(Sub.class):
+
+ // Sub<X, Y>.getSupertype(Base.class) => Base<X, Y>
+ // => X=String, Y=Integer
+ // => Sub<X, Y>=Sub<String, Integer>
+ TypeToken<?> genericSubtype = toGenericType(subclass);
+ @SuppressWarnings({"rawtypes", "unchecked"}) // subclass isn't <? extends T>
+ Type supertypeWithArgsFromSubtype = genericSubtype
+ .getSupertype((Class) getRawType())
+ .runtimeType;
+ return new TypeResolver().where(supertypeWithArgsFromSubtype, runtimeType)
+ .resolveType(genericSubtype.runtimeType);
+ }
+
+ /**
+ * Creates an array class if {@code componentType} is a class, or else, a
+ * {@link GenericArrayType}. This is what Java7 does for generic array type
+ * parameters.
+ */
+ private static Type newArrayClassOrGenericArrayType(Type componentType) {
+ return Types.JavaVersion.JAVA7.newArrayType(componentType);
+ }
+
+ private static final class SimpleTypeToken<T> extends TypeToken<T> {
+
+ SimpleTypeToken(Type type) {
+ super(type);
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Collects parent types from a sub type.
+ *
+ * @param <K> The type "kind". Either a TypeToken, or Class.
+ */
+ private abstract static class TypeCollector<K> {
+
+ static final TypeCollector<TypeToken<?>> FOR_GENERIC_TYPE =
+ new TypeCollector<TypeToken<?>>() {
+ @Override Class<?> getRawType(TypeToken<?> type) {
+ return type.getRawType();
+ }
+
+ @Override Iterable<? extends TypeToken<?>> getInterfaces(TypeToken<?> type) {
+ return type.getGenericInterfaces();
+ }
+
+ @Nullable
+ @Override TypeToken<?> getSuperclass(TypeToken<?> type) {
+ return type.getGenericSuperclass();
+ }
+ };
+
+ static final TypeCollector<Class<?>> FOR_RAW_TYPE =
+ new TypeCollector<Class<?>>() {
+ @Override Class<?> getRawType(Class<?> type) {
+ return type;
+ }
+
+ @Override Iterable<? extends Class<?>> getInterfaces(Class<?> type) {
+ return Arrays.asList(type.getInterfaces());
+ }
+
+ @Nullable
+ @Override Class<?> getSuperclass(Class<?> type) {
+ return type.getSuperclass();
+ }
+ };
+
+ /** For just classes, we don't have to traverse interfaces. */
+ final TypeCollector<K> classesOnly() {
+ return new ForwardingTypeCollector<K>(this) {
+ @Override Iterable<? extends K> getInterfaces(K type) {
+ return ImmutableSet.of();
+ }
+ @Override ImmutableList<K> collectTypes(Iterable<? extends K> types) {
+ ImmutableList.Builder<K> builder = ImmutableList.builder();
+ for (K type : types) {
+ if (!getRawType(type).isInterface()) {
+ builder.add(type);
+ }
+ }
+ return super.collectTypes(builder.build());
+ }
+ };
+ }
+
+ final ImmutableList<K> collectTypes(K type) {
+ return collectTypes(ImmutableList.of(type));
+ }
+
+ ImmutableList<K> collectTypes(Iterable<? extends K> types) {
+ // type -> order number. 1 for Object, 2 for anything directly below, so on so forth.
+ Map<K, Integer> map = Maps.newHashMap();
+ for (K type : types) {
+ collectTypes(type, map);
+ }
+ return sortKeysByValue(map, Ordering.natural().reverse());
+ }
+
+ /** Collects all types to map, and returns the total depth from T up to Object. */
+ private int collectTypes(K type, Map<? super K, Integer> map) {
+ Integer existing = map.get(this);
+ if (existing != null) {
+ // short circuit: if set contains type it already contains its supertypes
+ return existing;
+ }
+ int aboveMe = getRawType(type).isInterface()
+ ? 1 // interfaces should be listed before Object
+ : 0;
+ for (K interfaceType : getInterfaces(type)) {
+ aboveMe = Math.max(aboveMe, collectTypes(interfaceType, map));
+ }
+ K superclass = getSuperclass(type);
+ if (superclass != null) {
+ aboveMe = Math.max(aboveMe, collectTypes(superclass, map));
+ }
+ // TODO(benyu): should we include Object for interface?
+ // Also, CharSequence[] and Object[] for String[]?
+ map.put(type, aboveMe + 1);
+ return aboveMe + 1;
+ }
+
+ private static <K, V> ImmutableList<K> sortKeysByValue(
+ final Map<K, V> map, final Comparator<? super V> valueComparator) {
+ Ordering<K> keyOrdering = new Ordering<K>() {
+ @Override public int compare(K left, K right) {
+ return valueComparator.compare(map.get(left), map.get(right));
+ }
+ };
+ return keyOrdering.immutableSortedCopy(map.keySet());
+ }
+
+ abstract Class<?> getRawType(K type);
+ abstract Iterable<? extends K> getInterfaces(K type);
+ @Nullable abstract K getSuperclass(K type);
+
+ private static class ForwardingTypeCollector<K> extends TypeCollector<K> {
+
+ private final TypeCollector<K> delegate;
+
+ ForwardingTypeCollector(TypeCollector<K> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override Class<?> getRawType(K type) {
+ return delegate.getRawType(type);
+ }
+
+ @Override Iterable<? extends K> getInterfaces(K type) {
+ return delegate.getInterfaces(type);
+ }
+
+ @Override K getSuperclass(K type) {
+ return delegate.getSuperclass(type);
+ }
+ }
+ }
+}
diff --git a/guava/src/com/google/common/reflect/Types.java b/guava/src/com/google/common/reflect/Types.java
new file mode 100644
index 0000000..19264d3
--- /dev/null
+++ b/guava/src/com/google/common/reflect/Types.java
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2011 The Guava 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 com.google.common.reflect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.transform;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.annotation.Nullable;
+
+/**
+ * Utilities for working with {@link Type}.
+ *
+ * @author Ben Yu
+ */
+final class Types {
+
+ /** Class#toString without the "class " and "interface " prefixes */
+ private static final Function<Type, String> TYPE_TO_STRING =
+ new Function<Type, String>() {
+ @Override public String apply(Type from) {
+ return Types.toString(from);
+ }
+ };
+
+ private static final Joiner COMMA_JOINER = Joiner.on(", ").useForNull("null");
+
+ /** Returns the array type of {@code componentType}. */
+ static Type newArrayType(Type componentType) {
+ if (componentType instanceof WildcardType) {
+ WildcardType wildcard = (WildcardType) componentType;
+ Type[] lowerBounds = wildcard.getLowerBounds();
+ checkArgument(lowerBounds.length <= 1, "Wildcard cannot have more than one lower bounds.");
+ if (lowerBounds.length == 1) {
+ return supertypeOf(newArrayType(lowerBounds[0]));
+ } else {
+ Type[] upperBounds = wildcard.getUpperBounds();
+ checkArgument(upperBounds.length == 1, "Wildcard should have only one upper bound.");
+ return subtypeOf(newArrayType(upperBounds[0]));
+ }
+ }
+ return JavaVersion.CURRENT.newArrayType(componentType);
+ }
+
+ /**
+ * Returns a type where {@code rawType} is parameterized by
+ * {@code arguments} and is owned by {@code ownerType}.
+ */
+ static ParameterizedType newParameterizedTypeWithOwner(
+ @Nullable Type ownerType, Class<?> rawType, Type... arguments) {
+ if (ownerType == null) {
+ return newParameterizedType(rawType, arguments);
+ }
+ // ParameterizedTypeImpl constructor already checks, but we want to throw NPE before IAE
+ checkNotNull(arguments);
+ checkArgument(rawType.getEnclosingClass() != null, "Owner type for unenclosed %s", rawType);
+ return new ParameterizedTypeImpl(ownerType, rawType, arguments);
+ }
+
+ /**
+ * Returns a type where {@code rawType} is parameterized by
+ * {@code arguments}.
+ */
+ static ParameterizedType newParameterizedType(Class<?> rawType, Type... arguments) {
+ return new ParameterizedTypeImpl(
+ ClassOwnership.JVM_BEHAVIOR.getOwnerType(rawType), rawType, arguments);
+ }
+
+ /** Decides what owner type to use for constructing {@link ParameterizedType} from a raw class. */
+ private enum ClassOwnership {
+
+ OWNED_BY_ENCLOSING_CLASS {
+ @Nullable
+ @Override
+ Class<?> getOwnerType(Class<?> rawType) {
+ return rawType.getEnclosingClass();
+ }
+ },
+ LOCAL_CLASS_HAS_NO_OWNER {
+ @Nullable
+ @Override
+ Class<?> getOwnerType(Class<?> rawType) {
+ if (rawType.isLocalClass()) {
+ return null;
+ } else {
+ return rawType.getEnclosingClass();
+ }
+ }
+ };
+
+ @Nullable abstract Class<?> getOwnerType(Class<?> rawType);
+
+ static final ClassOwnership JVM_BEHAVIOR = detectJvmBehavior();
+
+ private static ClassOwnership detectJvmBehavior() {
+ class LocalClass<T> {}
+ Class<?> subclass = new LocalClass<String>() {}.getClass();
+ ParameterizedType parameterizedType = (ParameterizedType)
+ subclass.getGenericSuperclass();
+ for (ClassOwnership behavior : ClassOwnership.values()) {
+ if (behavior.getOwnerType(LocalClass.class) == parameterizedType.getOwnerType()) {
+ return behavior;
+ }
+ }
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Returns a new {@link TypeVariable} that belongs to {@code declaration} with
+ * {@code name} and {@code bounds}.
+ */
+ static <D extends GenericDeclaration> TypeVariable<D> newTypeVariable(
+ D declaration, String name, Type... bounds) {
+ return new TypeVariableImpl<D>(
+ declaration,
+ name,
+ (bounds.length == 0)
+ ? new Type[] { Object.class }
+ : bounds);
+ }
+
+ /** Returns a new {@link WildcardType} with {@code upperBound}. */
+ @VisibleForTesting static WildcardType subtypeOf(Type upperBound) {
+ return new WildcardTypeImpl(new Type[0], new Type[] { upperBound });
+ }
+
+ /** Returns a new {@link WildcardType} with {@code lowerBound}. */
+ @VisibleForTesting static WildcardType supertypeOf(Type lowerBound) {
+ return new WildcardTypeImpl(new Type[] { lowerBound }, new Type[] { Object.class });
+ }
+
+ /**
+ * Returns human readable string representation of {@code type}.
+ * <ul>
+ * <li> For array type {@code Foo[]}, {@code "com.mypackage.Foo[]"} are
+ * returned.
+ * <li> For any class, {@code theClass.getName()} are returned.
+ * <li> For all other types, {@code type.toString()} are returned.
+ * </ul>
+ */
+ static String toString(Type type) {
+ return (type instanceof Class)
+ ? ((Class<?>) type).getName()
+ : type.toString();
+ }
+
+ @Nullable static Type getComponentType(Type type) {
+ checkNotNull(type);
+ if (type instanceof Class) {
+ return ((Class<?>) type).getComponentType();
+ } else if (type instanceof GenericArrayType) {
+ return ((GenericArrayType) type).getGenericComponentType();
+ } else if (type instanceof WildcardType) {
+ return subtypeOfComponentType(((WildcardType) type).getUpperBounds());
+ } else if (type instanceof TypeVariable) {
+ return subtypeOfComponentType(((TypeVariable<?>) type).getBounds());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns {@code ? extends X} if any of {@code bounds} is a subtype of {@code X[]}; or null
+ * otherwise.
+ */
+ @Nullable private static Type subtypeOfComponentType(Type[] bounds) {
+ for (Type bound : bounds) {
+ Type componentType = getComponentType(bound);
+ if (componentType != null) {
+ // Only the first bound can be a class or array.
+ // Bounds after the first can only be interfaces.
+ if (componentType instanceof Class) {
+ Class<?> componentClass = (Class<?>) componentType;
+ if (componentClass.isPrimitive()) {
+ return componentClass;
+ }
+ }
+ return subtypeOf(componentType);
+ }
+ }
+ return null;
+ }
+
+ static boolean containsTypeVariable(@Nullable Type type) {
+ if (type instanceof TypeVariable) {
+ return true;
+ }
+ if (type instanceof GenericArrayType) {
+ return containsTypeVariable(((GenericArrayType) type).getGenericComponentType());
+ }
+ if (type instanceof ParameterizedType) {
+ return containsTypeVariable(((ParameterizedType) type).getActualTypeArguments());
+ }
+ if (type instanceof WildcardType) {
+ WildcardType wildcard = (WildcardType) type;
+ return containsTypeVariable(wildcard.getUpperBounds())
+ || containsTypeVariable(wildcard.getLowerBounds());
+ }
+ return false;
+ }
+
+ private static boolean containsTypeVariable(Type[] types) {
+ for (Type paramType : types) {
+ if (containsTypeVariable(paramType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static final class GenericArrayTypeImpl
+ implements GenericArrayType, Serializable {
+
+ private final Type componentType;
+
+ GenericArrayTypeImpl(Type componentType) {
+ this.componentType = JavaVersion.CURRENT.usedInGenericType(componentType);
+ }
+
+ @Override public Type getGenericComponentType() {
+ return componentType;
+ }
+
+ @Override public String toString() {
+ return Types.toString(componentType) + "[]";
+ }
+
+ @Override public int hashCode() {
+ return componentType.hashCode();
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof GenericArrayType) {
+ GenericArrayType that = (GenericArrayType) obj;
+ return Objects.equal(
+ getGenericComponentType(), that.getGenericComponentType());
+ }
+ return false;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static final class ParameterizedTypeImpl
+ implements ParameterizedType, Serializable {
+
+ private final Type ownerType;
+ private final ImmutableList<Type> argumentsList;
+ private final Class<?> rawType;
+
+ ParameterizedTypeImpl(
+ @Nullable Type ownerType, Class<?> rawType, Type[] typeArguments) {
+ checkNotNull(rawType);
+ checkArgument(typeArguments.length == rawType.getTypeParameters().length);
+ disallowPrimitiveType(typeArguments, "type parameter");
+ this.ownerType = ownerType;
+ this.rawType = rawType;
+ this.argumentsList = JavaVersion.CURRENT.usedInGenericType(typeArguments);
+ }
+
+ @Override public Type[] getActualTypeArguments() {
+ return toArray(argumentsList);
+ }
+
+ @Override public Type getRawType() {
+ return rawType;
+ }
+
+ @Override public Type getOwnerType() {
+ return ownerType;
+ }
+
+ @Override public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (ownerType != null) {
+ builder.append(Types.toString(ownerType)).append('.');
+ }
+ builder.append(rawType.getName())
+ .append('<')
+ .append(COMMA_JOINER.join(transform(argumentsList, TYPE_TO_STRING)))
+ .append('>');
+ return builder.toString();
+ }
+
+ @Override public int hashCode() {
+ return (ownerType == null ? 0 : ownerType.hashCode())
+ ^ argumentsList.hashCode() ^ rawType.hashCode();
+ }
+
+ @Override public boolean equals(Object other) {
+ if (!(other instanceof ParameterizedType)) {
+ return false;
+ }
+ ParameterizedType that = (ParameterizedType) other;
+ return getRawType().equals(that.getRawType())
+ && Objects.equal(getOwnerType(), that.getOwnerType())
+ && Arrays.equals(
+ getActualTypeArguments(), that.getActualTypeArguments());
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static final class TypeVariableImpl<D extends GenericDeclaration>
+ implements TypeVariable<D> {
+
+ private final D genericDeclaration;
+ private final String name;
+ private final ImmutableList<Type> bounds;
+
+ TypeVariableImpl(D genericDeclaration, String name, Type[] bounds) {
+ disallowPrimitiveType(bounds, "bound for type variable");
+ this.genericDeclaration = checkNotNull(genericDeclaration);
+ this.name = checkNotNull(name);
+ this.bounds = ImmutableList.copyOf(bounds);
+ }
+
+ @Override public Type[] getBounds() {
+ return toArray(bounds);
+ }
+
+ @Override public D getGenericDeclaration() {
+ return genericDeclaration;
+ }
+
+ @Override public String getName() {
+ return name;
+ }
+
+ @Override public String toString() {
+ return name;
+ }
+
+ @Override public int hashCode() {
+ return genericDeclaration.hashCode() ^ name.hashCode();
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof TypeVariable) {
+ TypeVariable<?> that = (TypeVariable<?>) obj;
+ return name.equals(that.getName())
+ && genericDeclaration.equals(that.getGenericDeclaration());
+ }
+ return false;
+ }
+ }
+
+ static final class WildcardTypeImpl implements WildcardType, Serializable {
+
+ private final ImmutableList<Type> lowerBounds;
+ private final ImmutableList<Type> upperBounds;
+
+ WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
+ disallowPrimitiveType(lowerBounds, "lower bound for wildcard");
+ disallowPrimitiveType(upperBounds, "upper bound for wildcard");
+ this.lowerBounds = JavaVersion.CURRENT.usedInGenericType(lowerBounds);
+ this.upperBounds = JavaVersion.CURRENT.usedInGenericType(upperBounds);
+ }
+
+ @Override public Type[] getLowerBounds() {
+ return toArray(lowerBounds);
+ }
+
+ @Override public Type[] getUpperBounds() {
+ return toArray(upperBounds);
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof WildcardType) {
+ WildcardType that = (WildcardType) obj;
+ return lowerBounds.equals(Arrays.asList(that.getLowerBounds()))
+ && upperBounds.equals(Arrays.asList(that.getUpperBounds()));
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return lowerBounds.hashCode() ^ upperBounds.hashCode();
+ }
+
+ @Override public String toString() {
+ StringBuilder builder = new StringBuilder("?");
+ for (Type lowerBound : lowerBounds) {
+ builder.append(" super ").append(Types.toString(lowerBound));
+ }
+ for (Type upperBound : filterUpperBounds(upperBounds)) {
+ builder.append(" extends ").append(Types.toString(upperBound));
+ }
+ return builder.toString();
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static Type[] toArray(Collection<Type> types) {
+ return types.toArray(new Type[types.size()]);
+ }
+
+ private static Iterable<Type> filterUpperBounds(Iterable<Type> bounds) {
+ return Iterables.filter(
+ bounds, Predicates.not(Predicates.<Type>equalTo(Object.class)));
+ }
+
+ private static void disallowPrimitiveType(Type[] types, String usedAs) {
+ for (Type type : types) {
+ if (type instanceof Class) {
+ Class<?> cls = (Class<?>) type;
+ checkArgument(!cls.isPrimitive(),
+ "Primitive type '%s' used as %s", cls, usedAs);
+ }
+ }
+ }
+
+ static IllegalArgumentException buildUnexpectedTypeException(
+ Type type, Class<?>... expected) {
+ // Build exception message
+ StringBuilder exceptionMessage =
+ new StringBuilder("Unexpected type. Expected one of: ");
+ for (Class<?> clazz : expected) {
+ exceptionMessage.append(clazz.getName()).append(", ");
+ }
+ exceptionMessage.append("but got: ").append(type.getClass().getName())
+ .append(", for type: ").append(toString(type)).append('.');
+
+ return new IllegalArgumentException(exceptionMessage.toString());
+ }
+
+ /** Returns the {@code Class} object of arrays with {@code componentType}. */
+ static Class<?> getArrayClass(Class<?> componentType) {
+ // TODO(user): This is not the most efficient way to handle generic
+ // arrays, but is there another way to extract the array class in a
+ // non-hacky way (i.e. using String value class names- "[L...")?
+ return Array.newInstance(componentType, 0).getClass();
+ }
+
+ // TODO(benyu): Once we are on Java 7, delete this abstraction
+ enum JavaVersion {
+
+ JAVA6 {
+ @Override GenericArrayType newArrayType(Type componentType) {
+ return new GenericArrayTypeImpl(componentType);
+ }
+ @Override Type usedInGenericType(Type type) {
+ checkNotNull(type);
+ if (type instanceof Class) {
+ Class<?> cls = (Class<?>) type;
+ if (cls.isArray()) {
+ return new GenericArrayTypeImpl(cls.getComponentType());
+ }
+ }
+ return type;
+ }
+ },
+ JAVA7 {
+ @Override Type newArrayType(Type componentType) {
+ if (componentType instanceof Class) {
+ return getArrayClass((Class<?>) componentType);
+ } else {
+ return new GenericArrayTypeImpl(componentType);
+ }
+ }
+ @Override Type usedInGenericType(Type type) {
+ return checkNotNull(type);
+ }
+ }
+ ;
+
+ static final JavaVersion CURRENT =
+ (new TypeCapture<int[]>() {}.capture() instanceof Class)
+ ? JAVA7 : JAVA6;
+ abstract Type newArrayType(Type componentType);
+ abstract Type usedInGenericType(Type type);
+
+ final ImmutableList<Type> usedInGenericType(Type[] types) {
+ ImmutableList.Builder<Type> builder = ImmutableList.builder();
+ for (Type type : types) {
+ builder.add(usedInGenericType(type));
+ }
+ return builder.build();
+ }
+ }
+
+ private Types() {}
+}
diff --git a/guava/src/com/google/common/reflect/package-info.java b/guava/src/com/google/common/reflect/package-info.java
new file mode 100644
index 0000000..e8ac02a
--- /dev/null
+++ b/guava/src/com/google/common/reflect/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012 The Guava 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.
+ */
+
+/**
+ * This package contains utilities to work with Java reflection.
+ * It is a part of the open-source
+ * <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
+ */
+@javax.annotation.ParametersAreNonnullByDefault
+package com.google.common.reflect;