aboutsummaryrefslogtreecommitdiffstats
path: root/guava/src/com/google/common/reflect
diff options
context:
space:
mode:
authorPaul Duffin <paulduffin@google.com>2015-01-06 16:17:43 +0000
committerPaul Duffin <paulduffin@google.com>2015-01-08 14:36:14 +0000
commit3c77433663281544363151bf284b0240dfd22a42 (patch)
tree80bc061726b4720c9bf713a2a494920b393c2a7e /guava/src/com/google/common/reflect
parent5e6db342fc75b1945298142530f2d1d1861bce73 (diff)
downloadandroid_external_guava-3c77433663281544363151bf284b0240dfd22a42.tar.gz
android_external_guava-3c77433663281544363151bf284b0240dfd22a42.tar.bz2
android_external_guava-3c77433663281544363151bf284b0240dfd22a42.zip
Upgraded Guava to unmodified v14.0.1
This simply copies the Guava source for v14.0.1 straight from its github repository into this one. Additional commits will be made which will allow this to compile on Android. Change-Id: If0a8231e1d9530b7bdd94474403f7055e013979f
Diffstat (limited to 'guava/src/com/google/common/reflect')
-rw-r--r--guava/src/com/google/common/reflect/AbstractInvocationHandler.java112
-rw-r--r--guava/src/com/google/common/reflect/ClassPath.java379
-rw-r--r--guava/src/com/google/common/reflect/Element.java164
-rw-r--r--guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java138
-rw-r--r--guava/src/com/google/common/reflect/Invokable.java286
-rw-r--r--guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java89
-rw-r--r--guava/src/com/google/common/reflect/Parameter.java103
-rw-r--r--guava/src/com/google/common/reflect/Reflection.java98
-rw-r--r--guava/src/com/google/common/reflect/TypeCapture.java38
-rw-r--r--guava/src/com/google/common/reflect/TypeParameter.java67
-rw-r--r--guava/src/com/google/common/reflect/TypeResolver.java391
-rw-r--r--guava/src/com/google/common/reflect/TypeToInstanceMap.java92
-rw-r--r--guava/src/com/google/common/reflect/TypeToken.java1146
-rw-r--r--guava/src/com/google/common/reflect/Types.java504
-rw-r--r--guava/src/com/google/common/reflect/package-info.java23
15 files changed, 3630 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..489dcff
--- /dev/null
+++ b/guava/src/com/google/common/reflect/AbstractInvocationHandler.java
@@ -0,0 +1,112 @@
+/*
+ * 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 java.lang.reflect.Proxy;
+
+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><ul>
+ * <li>{@code proxy.hashCode()} delegates to {@link AbstractInvocationHandler#hashCode}
+ * <li>{@code proxy.toString()} delegates to {@link AbstractInvocationHandler#toString}
+ * <li>{@code proxy.equals(argument)} returns true if: <ul>
+ * <li>{@code proxy} and {@code argument} are of the same type
+ * <li>and {@link AbstractInvocationHandler#equals} returns true for the {@link
+ * InvocationHandler} of {@code argument}
+ * </ul>
+ * <li>other method calls are dispatched to {@link #handleInvocation}.
+ * </ul>
+ */
+ @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 hashCode();
+ }
+ if (args.length == 1
+ && method.getName().equals("equals")
+ && method.getParameterTypes()[0] == Object.class) {
+ Object arg = args[0];
+ return proxy.getClass().isInstance(arg) && equals(Proxy.getInvocationHandler(arg));
+ }
+ 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;
+
+ /**
+ * By default delegates to {@link Object#equals} so instances are only equal if they are
+ * identical. {@code proxy.equals(argument)} returns true if: <ul>
+ * <li>{@code proxy} and {@code argument} are of the same type
+ * <li>and this method returns true for the {@link InvocationHandler} of {@code argument}
+ * </ul>
+ * Subclasses can override this method to provide custom equality.
+ */
+ @Override public boolean equals(Object obj) {
+ return super.equals(obj);
+ }
+
+ /**
+ * By default delegates to {@link Object#hashCode}. The dynamic proxies' {@code hashCode()} will
+ * delegate to this method. Subclasses can override this method to provide custom equality.
+ */
+ @Override public int hashCode() {
+ return super.hashCode();
+ }
+
+ /**
+ * By default delegates to {@link Object#toString}. The dynamic proxies' {@code toString()} will
+ * delegate to this method. Subclasses can override this method to provide custom string
+ * representation for the proxies.
+ */
+ @Override public String toString() {
+ return super.toString();
+ }
+}
diff --git a/guava/src/com/google/common/reflect/ClassPath.java b/guava/src/com/google/common/reflect/ClassPath.java
new file mode 100644
index 0000000..cfbc479
--- /dev/null
+++ b/guava/src/com/google/common/reflect/ClassPath.java
@@ -0,0 +1,379 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Ordering;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.logging.Logger;
+
+import javax.annotation.Nullable;
+
+/**
+ * Scans the source of a {@link ClassLoader} and finds all the classes loadable.
+ *
+ * @author Ben Yu
+ * @since 14.0
+ */
+@Beta
+public final class ClassPath {
+
+ private static final Logger logger = Logger.getLogger(ClassPath.class.getName());
+
+ /** Separator for the Class-Path manifest attribute value in jar files. */
+ private static final Splitter CLASS_PATH_ATTRIBUTE_SEPARATOR =
+ Splitter.on(" ").omitEmptyStrings();
+
+ private static final String CLASS_FILE_NAME_EXTENSION = ".class";
+
+ private final ImmutableSet<ResourceInfo> resources;
+
+ private ClassPath(ImmutableSet<ResourceInfo> resources) {
+ this.resources = resources;
+ }
+
+ /**
+ * Returns a {@code ClassPath} representing all classes and resources loadable from {@code
+ * classloader} and its parent class loaders.
+ *
+ * <p>Currently only {@link URLClassLoader} and only {@code file://} urls are supported.
+ *
+ * @throws IOException if the attempt to read class path resources (jar files or directories)
+ * failed.
+ */
+ public static ClassPath from(ClassLoader classloader) throws IOException {
+ ImmutableSortedSet.Builder<ResourceInfo> resources =
+ new ImmutableSortedSet.Builder<ResourceInfo>(Ordering.usingToString());
+ for (Map.Entry<URI, ClassLoader> entry : getClassPathEntries(classloader).entrySet()) {
+ browse(entry.getKey(), entry.getValue(), resources);
+ }
+ return new ClassPath(resources.build());
+ }
+
+ /**
+ * Returns all resources loadable from the current class path, including the class files of all
+ * loadable classes.
+ */
+ public ImmutableSet<ResourceInfo> getResources() {
+ return resources;
+ }
+
+ /** Returns all top level classes loadable from the current class path. */
+ public ImmutableSet<ClassInfo> getTopLevelClasses() {
+ ImmutableSet.Builder<ClassInfo> builder = ImmutableSet.builder();
+ for (ResourceInfo resource : resources) {
+ if (resource instanceof ClassInfo) {
+ builder.add((ClassInfo) resource);
+ }
+ }
+ return builder.build();
+ }
+
+ /** Returns all top level classes whose package name is {@code packageName}. */
+ public ImmutableSet<ClassInfo> getTopLevelClasses(String packageName) {
+ checkNotNull(packageName);
+ ImmutableSet.Builder<ClassInfo> builder = ImmutableSet.builder();
+ for (ClassInfo classInfo : getTopLevelClasses()) {
+ if (classInfo.getPackageName().equals(packageName)) {
+ builder.add(classInfo);
+ }
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns all top level classes whose package name is {@code packageName} or starts with
+ * {@code packageName} followed by a '.'.
+ */
+ public ImmutableSet<ClassInfo> getTopLevelClassesRecursive(String packageName) {
+ checkNotNull(packageName);
+ String packagePrefix = packageName + '.';
+ ImmutableSet.Builder<ClassInfo> builder = ImmutableSet.builder();
+ for (ClassInfo classInfo : getTopLevelClasses()) {
+ if (classInfo.getName().startsWith(packagePrefix)) {
+ builder.add(classInfo);
+ }
+ }
+ return builder.build();
+ }
+
+ /**
+ * Represents a class path resource that can be either a class file or any other resource file
+ * loadable from the class path.
+ *
+ * @since 14.0
+ */
+ @Beta
+ public static class ResourceInfo {
+ private final String resourceName;
+ final ClassLoader loader;
+
+ static ResourceInfo of(String resourceName, ClassLoader loader) {
+ if (resourceName.endsWith(CLASS_FILE_NAME_EXTENSION) && !resourceName.contains("$")) {
+ return new ClassInfo(resourceName, loader);
+ } else {
+ return new ResourceInfo(resourceName, loader);
+ }
+ }
+
+ ResourceInfo(String resourceName, ClassLoader loader) {
+ this.resourceName = checkNotNull(resourceName);
+ this.loader = checkNotNull(loader);
+ }
+
+ /** Returns the url identifying the resource. */
+ public final URL url() {
+ return checkNotNull(loader.getResource(resourceName),
+ "Failed to load resource: %s", resourceName);
+ }
+
+ /** Returns the fully qualified name of the resource. Such as "com/mycomp/foo/bar.txt". */
+ public final String getResourceName() {
+ return resourceName;
+ }
+
+ @Override public int hashCode() {
+ return resourceName.hashCode();
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof ResourceInfo) {
+ ResourceInfo that = (ResourceInfo) obj;
+ return resourceName.equals(that.resourceName)
+ && loader == that.loader;
+ }
+ return false;
+ }
+
+ @Override public String toString() {
+ return resourceName;
+ }
+ }
+
+ /**
+ * Represents a class that can be loaded through {@link #load}.
+ *
+ * @since 14.0
+ */
+ @Beta
+ public static final class ClassInfo extends ResourceInfo {
+ private final String className;
+
+ ClassInfo(String resourceName, ClassLoader loader) {
+ super(resourceName, loader);
+ this.className = getClassName(resourceName);
+ }
+
+ /** Returns the package name of the class, without attempting to load the class. */
+ public String getPackageName() {
+ return Reflection.getPackageName(className);
+ }
+
+ /** Returns the simple name of the underlying class as given in the source code. */
+ public String getSimpleName() {
+ String packageName = getPackageName();
+ if (packageName.isEmpty()) {
+ return className;
+ }
+ // Since this is a top level class, its simple name is always the part after package name.
+ return className.substring(packageName.length() + 1);
+ }
+
+ /** Returns the fully qualified name of the class. */
+ public String getName() {
+ return className;
+ }
+
+ /** Loads (but doesn't link or initialize) the class. */
+ public Class<?> load() {
+ try {
+ return loader.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ // Shouldn't happen, since the class name is read from the class path.
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public String toString() {
+ return className;
+ }
+ }
+
+ @VisibleForTesting static ImmutableMap<URI, ClassLoader> getClassPathEntries(
+ ClassLoader classloader) {
+ LinkedHashMap<URI, ClassLoader> entries = Maps.newLinkedHashMap();
+ // Search parent first, since it's the order ClassLoader#loadClass() uses.
+ ClassLoader parent = classloader.getParent();
+ if (parent != null) {
+ entries.putAll(getClassPathEntries(parent));
+ }
+ if (classloader instanceof URLClassLoader) {
+ URLClassLoader urlClassLoader = (URLClassLoader) classloader;
+ for (URL entry : urlClassLoader.getURLs()) {
+ URI uri;
+ try {
+ uri = entry.toURI();
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+ if (!entries.containsKey(uri)) {
+ entries.put(uri, classloader);
+ }
+ }
+ }
+ return ImmutableMap.copyOf(entries);
+ }
+
+ private static void browse(
+ URI uri, ClassLoader classloader, ImmutableSet.Builder<ResourceInfo> resources)
+ throws IOException {
+ if (uri.getScheme().equals("file")) {
+ browseFrom(new File(uri), classloader, resources);
+ }
+ }
+
+ @VisibleForTesting static void browseFrom(
+ File file, ClassLoader classloader, ImmutableSet.Builder<ResourceInfo> resources)
+ throws IOException {
+ if (!file.exists()) {
+ return;
+ }
+ if (file.isDirectory()) {
+ browseDirectory(file, classloader, resources);
+ } else {
+ browseJar(file, classloader, resources);
+ }
+ }
+
+ private static void browseDirectory(
+ File directory, ClassLoader classloader, ImmutableSet.Builder<ResourceInfo> resources) {
+ browseDirectory(directory, classloader, "", resources);
+ }
+
+ private static void browseDirectory(
+ File directory, ClassLoader classloader, String packagePrefix,
+ ImmutableSet.Builder<ResourceInfo> resources) {
+ for (File f : directory.listFiles()) {
+ String name = f.getName();
+ if (f.isDirectory()) {
+ browseDirectory(f, classloader, packagePrefix + name + "/", resources);
+ } else {
+ String resourceName = packagePrefix + name;
+ resources.add(ResourceInfo.of(resourceName, classloader));
+ }
+ }
+ }
+
+ private static void browseJar(
+ File file, ClassLoader classloader, ImmutableSet.Builder<ResourceInfo> resources)
+ throws IOException {
+ JarFile jarFile;
+ try {
+ jarFile = new JarFile(file);
+ } catch (IOException e) {
+ // Not a jar file
+ return;
+ }
+ try {
+ for (URI uri : getClassPathFromManifest(file, jarFile.getManifest())) {
+ browse(uri, classloader, resources);
+ }
+ Enumeration<JarEntry> entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ if (entry.isDirectory() || entry.getName().startsWith("META-INF/")) {
+ continue;
+ }
+ resources.add(ResourceInfo.of(entry.getName(), classloader));
+ }
+ } finally {
+ try {
+ jarFile.close();
+ } catch (IOException ignored) {}
+ }
+ }
+
+ /**
+ * Returns the class path URIs specified by the {@code Class-Path} manifest attribute, according
+ * to <a href="http://docs.oracle.com/javase/1.4.2/docs/guide/jar/jar.html#Main%20Attributes">
+ * JAR File Specification</a>. If {@code manifest} is null, it means the jar file has no manifest,
+ * and an empty set will be returned.
+ */
+ @VisibleForTesting static ImmutableSet<URI> getClassPathFromManifest(
+ File jarFile, @Nullable Manifest manifest) {
+ if (manifest == null) {
+ return ImmutableSet.of();
+ }
+ ImmutableSet.Builder<URI> builder = ImmutableSet.builder();
+ String classpathAttribute = manifest.getMainAttributes().getValue("Class-Path");
+ if (classpathAttribute != null) {
+ for (String path : CLASS_PATH_ATTRIBUTE_SEPARATOR.split(classpathAttribute)) {
+ URI uri;
+ try {
+ uri = getClassPathEntry(jarFile, path);
+ } catch (URISyntaxException e) {
+ // Ignore bad entry
+ logger.warning("Invalid Class-Path entry: " + path);
+ continue;
+ }
+ builder.add(uri);
+ }
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns the absolute uri of the Class-Path entry value as specified in
+ * <a href="http://docs.oracle.com/javase/1.4.2/docs/guide/jar/jar.html#Main%20Attributes">
+ * JAR File Specification</a>. Even though the specification only talks about relative urls,
+ * absolute urls are actually supported too (for example, in Maven surefire plugin).
+ */
+ @VisibleForTesting static URI getClassPathEntry(File jarFile, String path)
+ throws URISyntaxException {
+ URI uri = new URI(path);
+ if (uri.isAbsolute()) {
+ return uri;
+ } else {
+ return new File(jarFile.getParentFile(), path.replace('/', File.separatorChar)).toURI();
+ }
+ }
+
+ @VisibleForTesting static String getClassName(String filename) {
+ int classNameEnd = filename.length() - CLASS_FILE_NAME_EXTENSION.length();
+ return filename.substring(0, classNameEnd).replace('/', '.');
+ }
+}
diff --git a/guava/src/com/google/common/reflect/Element.java b/guava/src/com/google/common/reflect/Element.java
new file mode 100644
index 0000000..14962b6
--- /dev/null
+++ b/guava/src/com/google/common/reflect/Element.java
@@ -0,0 +1,164 @@
+/*
+ * 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.checkNotNull;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import javax.annotation.Nullable;
+
+/**
+ * Represents either a {@link Field}, a {@link Method} or a {@link Constructor}.
+ * Provides convenience methods such as {@link #isPublic} and {@link #isPackagePrivate}.
+ *
+ * @author Ben Yu
+ */
+class Element extends AccessibleObject implements Member {
+
+ private final AccessibleObject accessibleObject;
+ private final Member member;
+
+ <M extends AccessibleObject & Member> Element(M member) {
+ checkNotNull(member);
+ this.accessibleObject = member;
+ this.member = member;
+ }
+
+ @Override public final boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
+ return accessibleObject.isAnnotationPresent(annotationClass);
+ }
+
+ @Override public final <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
+ return accessibleObject.getAnnotation(annotationClass);
+ }
+
+ @Override public final Annotation[] getAnnotations() {
+ return accessibleObject.getAnnotations();
+ }
+
+ @Override public final Annotation[] getDeclaredAnnotations() {
+ return accessibleObject.getDeclaredAnnotations();
+ }
+
+ @Override public final void setAccessible(boolean flag) throws SecurityException {
+ accessibleObject.setAccessible(flag);
+ }
+
+ @Override public final boolean isAccessible() {
+ return accessibleObject.isAccessible();
+ }
+
+ @Override public Class<?> getDeclaringClass() {
+ return member.getDeclaringClass();
+ }
+
+ @Override public final String getName() {
+ return member.getName();
+ }
+
+ @Override public final int getModifiers() {
+ return member.getModifiers();
+ }
+
+ @Override public final boolean isSynthetic() {
+ return member.isSynthetic();
+ }
+
+ /** Returns true if the element is public. */
+ public final boolean isPublic() {
+ return Modifier.isPublic(getModifiers());
+ }
+
+ /** Returns true if the element is protected. */
+ public final boolean isProtected() {
+ return Modifier.isProtected(getModifiers());
+ }
+
+ /** Returns true if the element is package-private. */
+ public final boolean isPackagePrivate() {
+ return !isPrivate() && !isPublic() && !isProtected();
+ }
+
+ /** Returns true if the element is private. */
+ public final boolean isPrivate() {
+ return Modifier.isPrivate(getModifiers());
+ }
+
+ /** Returns true if the element is static. */
+ public final boolean isStatic() {
+ return Modifier.isStatic(getModifiers());
+ }
+
+ /**
+ * Returns {@code true} if this method is final, per {@code Modifier.isFinal(getModifiers())}.
+ *
+ * <p>Note that a method may still be effectively "final", or non-overridable when it has no
+ * {@code final} keyword. For example, it could be private, or it could be declared by a final
+ * class. To tell whether a method is overridable, use {@link Invokable#isOverridable}.
+ */
+ public final boolean isFinal() {
+ return Modifier.isFinal(getModifiers());
+ }
+
+ /** Returns true if the method is abstract. */
+ public final boolean isAbstract() {
+ return Modifier.isAbstract(getModifiers());
+ }
+
+ /** Returns true if the element is native. */
+ public final boolean isNative() {
+ return Modifier.isNative(getModifiers());
+ }
+
+ /** Returns true if the method is synchronized. */
+ public final boolean isSynchronized() {
+ return Modifier.isSynchronized(getModifiers());
+ }
+
+ /** Returns true if the field is volatile. */
+ final boolean isVolatile() {
+ return Modifier.isVolatile(getModifiers());
+ }
+
+ /** Returns true if the field is transient. */
+ final boolean isTransient() {
+ return Modifier.isTransient(getModifiers());
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof Element) {
+ Element that = (Element) obj;
+ return member.equals(that.member);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return member.hashCode();
+ }
+
+ @Override public String toString() {
+ return member.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/Invokable.java b/guava/src/com/google/common/reflect/Invokable.java
new file mode 100644
index 0000000..a8f9b77
--- /dev/null
+++ b/guava/src/com/google/common/reflect/Invokable.java
@@ -0,0 +1,286 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Arrays;
+
+import javax.annotation.Nullable;
+
+/**
+ * Wrapper around either a {@link Method} or a {@link Constructor}.
+ * Convenience API is provided to make common reflective operation easier to deal with,
+ * such as {@link #isPublic}, {@link #getParameters} etc.
+ *
+ * <p>In addition to convenience methods, {@link TypeToken#method} and {@link
+ * TypeToken#constructor} will resolve the type parameters of the method or constructor in the
+ * context of the owner type, which may be a subtype of the declaring class. For example:
+ * <pre> {@code
+ *
+ * Method getMethod = List.class.getMethod("get", int.class);
+ * Invokable<List<String>, ?> invokable = new TypeToken<List<String>>() {}.method(getMethod);
+ * assertEquals(TypeToken.of(String.class), invokable.getReturnType()); // Not Object.class!
+ * assertEquals(new TypeToken<List<String>>() {}, invokable.getOwnerType());}</pre>
+ *
+ * @param <T> the type that owns this method or constructor.
+ * @param <R> the return type of (or supertype thereof) the method or the declaring type of the
+ * constructor.
+ * @author Ben Yu
+ * @since 14.0
+ */
+@Beta
+public abstract class Invokable<T, R> extends Element implements GenericDeclaration {
+
+ <M extends AccessibleObject & Member> Invokable(M member) {
+ super(member);
+ }
+
+ /** Returns {@link Invokable} of {@code method}. */
+ public static Invokable<?, Object> from(Method method) {
+ return new MethodInvokable<Object>(method);
+ }
+
+ /** Returns {@link Invokable} of {@code constructor}. */
+ public static <T> Invokable<T, T> from(Constructor<T> constructor) {
+ return new ConstructorInvokable<T>(constructor);
+ }
+
+ /**
+ * Returns {@code true} if this is an overridable method. Constructors, private, static or final
+ * methods, or methods declared by final classes are not overridable.
+ */
+ public abstract boolean isOverridable();
+
+ /** Returns {@code true} if this was declared to take a variable number of arguments. */
+ public abstract boolean isVarArgs();
+
+ /**
+ * Invokes with {@code receiver} as 'this' and {@code args} passed to the underlying method
+ * and returns the return value; or calls the underlying constructor with {@code args} and returns
+ * the constructed instance.
+ *
+ * @throws IllegalAccessException if this {@code Constructor} object enforces Java language
+ * access control and the underlying method or constructor is inaccessible.
+ * @throws IllegalArgumentException if the number of actual and formal parameters differ;
+ * if an unwrapping conversion for primitive arguments fails; or if, after possible
+ * unwrapping, a parameter value cannot be converted to the corresponding formal
+ * parameter type by a method invocation conversion.
+ * @throws InvocationTargetException if the underlying method or constructor throws an exception.
+ */
+ // All subclasses are owned by us and we'll make sure to get the R type right.
+ @SuppressWarnings("unchecked")
+ public final R invoke(@Nullable T receiver, Object... args)
+ throws InvocationTargetException, IllegalAccessException {
+ return (R) invokeInternal(receiver, checkNotNull(args));
+ }
+
+ /** Returns the return type of this {@code Invokable}. */
+ // All subclasses are owned by us and we'll make sure to get the R type right.
+ @SuppressWarnings("unchecked")
+ public final TypeToken<? extends R> getReturnType() {
+ return (TypeToken<? extends R>) TypeToken.of(getGenericReturnType());
+ }
+
+ /**
+ * Returns all declared parameters of this {@code Invokable}. Note that if this is a constructor
+ * of a non-static inner class, unlike {@link Constructor#getParameterTypes}, the hidden
+ * {@code this} parameter of the enclosing class is excluded from the returned parameters.
+ */
+ public final ImmutableList<Parameter> getParameters() {
+ Type[] parameterTypes = getGenericParameterTypes();
+ Annotation[][] annotations = getParameterAnnotations();
+ ImmutableList.Builder<Parameter> builder = ImmutableList.builder();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ builder.add(new Parameter(
+ this, i, TypeToken.of(parameterTypes[i]), annotations[i]));
+ }
+ return builder.build();
+ }
+
+ /** Returns all declared exception types of this {@code Invokable}. */
+ public final ImmutableList<TypeToken<? extends Throwable>> getExceptionTypes() {
+ ImmutableList.Builder<TypeToken<? extends Throwable>> builder = ImmutableList.builder();
+ for (Type type : getGenericExceptionTypes()) {
+ // getGenericExceptionTypes() will never return a type that's not exception
+ @SuppressWarnings("unchecked")
+ TypeToken<? extends Throwable> exceptionType = (TypeToken<? extends Throwable>)
+ TypeToken.of(type);
+ builder.add(exceptionType);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Explicitly specifies the return type of this {@code Invokable}. For example:
+ * <pre> {@code
+ * Method factoryMethod = Person.class.getMethod("create");
+ * Invokable<?, Person> factory = Invokable.of(getNameMethod).returning(Person.class);
+ * }</pre>
+ */
+ public final <R1 extends R> Invokable<T, R1> returning(Class<R1> returnType) {
+ return returning(TypeToken.of(returnType));
+ }
+
+ /** Explicitly specifies the return type of this {@code Invokable}. */
+ public final <R1 extends R> Invokable<T, R1> returning(TypeToken<R1> returnType) {
+ if (!returnType.isAssignableFrom(getReturnType())) {
+ throw new IllegalArgumentException(
+ "Invokable is known to return " + getReturnType() + ", not " + returnType);
+ }
+ @SuppressWarnings("unchecked") // guarded by previous check
+ Invokable<T, R1> specialized = (Invokable<T, R1>) this;
+ return specialized;
+ }
+
+ @SuppressWarnings("unchecked") // The declaring class is T's raw class, or one of its supertypes.
+ @Override public final Class<? super T> getDeclaringClass() {
+ return (Class<? super T>) super.getDeclaringClass();
+ }
+
+ /** Returns the type of {@code T}. */
+ // Overridden in TypeToken#method() and TypeToken#constructor()
+ @SuppressWarnings("unchecked") // The declaring class is T.
+ public TypeToken<T> getOwnerType() {
+ return (TypeToken<T>) TypeToken.of(getDeclaringClass());
+ }
+
+ abstract Object invokeInternal(@Nullable Object receiver, Object[] args)
+ throws InvocationTargetException, IllegalAccessException;
+
+ abstract Type[] getGenericParameterTypes();
+
+ /** This should never return a type that's not a subtype of Throwable. */
+ abstract Type[] getGenericExceptionTypes();
+
+ abstract Annotation[][] getParameterAnnotations();
+
+ abstract Type getGenericReturnType();
+
+ static class MethodInvokable<T> extends Invokable<T, Object> {
+
+ private final Method method;
+
+ MethodInvokable(Method method) {
+ super(method);
+ this.method = method;
+ }
+
+ @Override final Object invokeInternal(@Nullable Object receiver, Object[] args)
+ throws InvocationTargetException, IllegalAccessException {
+ return method.invoke(receiver, args);
+ }
+
+ @Override Type getGenericReturnType() {
+ return method.getGenericReturnType();
+ }
+
+ @Override Type[] getGenericParameterTypes() {
+ return method.getGenericParameterTypes();
+ }
+
+ @Override Type[] getGenericExceptionTypes() {
+ return method.getGenericExceptionTypes();
+ }
+
+ @Override final Annotation[][] getParameterAnnotations() {
+ return method.getParameterAnnotations();
+ }
+
+ @Override public final TypeVariable<?>[] getTypeParameters() {
+ return method.getTypeParameters();
+ }
+
+ @Override public final boolean isOverridable() {
+ return !(isFinal() || isPrivate() || isStatic()
+ || Modifier.isFinal(getDeclaringClass().getModifiers()));
+ }
+
+ @Override public final boolean isVarArgs() {
+ return method.isVarArgs();
+ }
+ }
+
+ static class ConstructorInvokable<T> extends Invokable<T, T> {
+
+ private final Constructor<?> constructor;
+
+ ConstructorInvokable(Constructor<?> constructor) {
+ super(constructor);
+ this.constructor = constructor;
+ }
+
+ @Override final Object invokeInternal(@Nullable Object receiver, Object[] args)
+ throws InvocationTargetException, IllegalAccessException {
+ try {
+ return constructor.newInstance(args);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(constructor + " failed.", e);
+ }
+ }
+
+ @Override Type getGenericReturnType() {
+ return constructor.getDeclaringClass();
+ }
+
+ @Override Type[] getGenericParameterTypes() {
+ Type[] types = constructor.getGenericParameterTypes();
+ Class<?> declaringClass = constructor.getDeclaringClass();
+ if (!Modifier.isStatic(declaringClass.getModifiers())
+ && declaringClass.getEnclosingClass() != null) {
+ if (types.length == constructor.getParameterTypes().length) {
+ // first parameter is the hidden 'this'
+ return Arrays.copyOfRange(types, 1, types.length);
+ }
+ }
+ return types;
+ }
+
+ @Override Type[] getGenericExceptionTypes() {
+ return constructor.getGenericExceptionTypes();
+ }
+
+ @Override final Annotation[][] getParameterAnnotations() {
+ return constructor.getParameterAnnotations();
+ }
+
+ @Override public final TypeVariable<?>[] getTypeParameters() {
+ return constructor.getTypeParameters();
+ }
+
+ @Override public final boolean isOverridable() {
+ return false;
+ }
+
+ @Override public final boolean isVarArgs() {
+ return constructor.isVarArgs();
+ }
+ }
+}
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/Parameter.java b/guava/src/com/google/common/reflect/Parameter.java
new file mode 100644
index 0000000..977bc8d
--- /dev/null
+++ b/guava/src/com/google/common/reflect/Parameter.java
@@ -0,0 +1,103 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+
+import javax.annotation.Nullable;
+
+/**
+ * Represents a method or constructor parameter.
+ *
+ * @author Ben Yu
+ * @since 14.0
+ */
+@Beta
+public final class Parameter implements AnnotatedElement {
+
+ private final Invokable<?, ?> declaration;
+ private final int position;
+ private final TypeToken<?> type;
+ private final ImmutableList<Annotation> annotations;
+
+ Parameter(
+ Invokable<?, ?> declaration,
+ int position,
+ TypeToken<?> type,
+ Annotation[] annotations) {
+ this.declaration = declaration;
+ this.position = position;
+ this.type = type;
+ this.annotations = ImmutableList.copyOf(annotations);
+ }
+
+ /** Returns the type of the parameter. */
+ public TypeToken<?> getType() {
+ return type;
+ }
+
+ /** Returns the {@link Invokable} that declares this parameter. */
+ public Invokable<?, ?> getDeclaringInvokable() {
+ return declaration;
+ }
+
+ @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+ return getAnnotation(annotationType) != null;
+ }
+
+ @Override
+ @Nullable
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ checkNotNull(annotationType);
+ for (Annotation annotation : annotations) {
+ if (annotationType.isInstance(annotation)) {
+ return annotationType.cast(annotation);
+ }
+ }
+ return null;
+ }
+
+ @Override public Annotation[] getAnnotations() {
+ return getDeclaredAnnotations();
+ }
+
+ @Override public Annotation[] getDeclaredAnnotations() {
+ return annotations.toArray(new Annotation[annotations.size()]);
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof Parameter) {
+ Parameter that = (Parameter) obj;
+ return position == that.position && declaration.equals(that.declaration);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return position;
+ }
+
+ @Override public String toString() {
+ return type + " arg" + position;
+ }
+}
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..028c8a9
--- /dev/null
+++ b/guava/src/com/google/common/reflect/Reflection.java
@@ -0,0 +1,98 @@
+/*
+ * 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 clazz} 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<?> clazz) {
+ return getPackageName(clazz.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('.');
+ return (lastDot < 0) ? "" : 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(handler);
+ checkArgument(interfaceType.isInterface(), "%s is not an interface", interfaceType);
+ 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..79bf076
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeParameter.java
@@ -0,0 +1,67 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+
+import javax.annotation.Nullable;
+
+/**
+ * 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;
+
+ 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(@Nullable 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..8c2d582
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeResolver.java
@@ -0,0 +1,391 @@
+/*
+ * 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, checkNotNull(formal), checkNotNull(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) {
+ checkNotNull(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) {
+ checkNotNull(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..61469b5
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeToken.java
@@ -0,0 +1,1146 @@
+/*
+ * 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.Constructor;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+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 Type[] resolveInPlace(Type[] types) {
+ for (int i = 0; i < types.length; i++) {
+ types[i] = resolveType(types[i]).getType();
+ }
+ return types;
+ }
+
+ 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);
+ }
+
+ /**
+ * Returns the {@link Invokable} for {@code method}, which must be a member of {@code T}.
+ *
+ * @since 14.0
+ */
+ public final Invokable<T, Object> method(Method method) {
+ checkArgument(of(method.getDeclaringClass()).isAssignableFrom(this),
+ "%s not declared by %s", method, this);
+ return new Invokable.MethodInvokable<T>(method) {
+ @Override Type getGenericReturnType() {
+ return resolveType(super.getGenericReturnType()).getType();
+ }
+ @Override Type[] getGenericParameterTypes() {
+ return resolveInPlace(super.getGenericParameterTypes());
+ }
+ @Override Type[] getGenericExceptionTypes() {
+ return resolveInPlace(super.getGenericExceptionTypes());
+ }
+ @Override public TypeToken<T> getOwnerType() {
+ return TypeToken.this;
+ }
+ };
+ }
+
+ /**
+ * Returns the {@link Invokable} for {@code constructor}, which must be a member of {@code T}.
+ *
+ * @since 14.0
+ */
+ public final Invokable<T, T> constructor(Constructor<?> constructor) {
+ checkArgument(constructor.getDeclaringClass() == getRawType(),
+ "%s not declared by %s", constructor, getRawType());
+ return new Invokable.ConstructorInvokable<T>(constructor) {
+ @Override Type getGenericReturnType() {
+ return resolveType(super.getGenericReturnType()).getType();
+ }
+ @Override Type[] getGenericParameterTypes() {
+ return resolveInPlace(super.getGenericParameterTypes());
+ }
+ @Override Type[] getGenericExceptionTypes() {
+ return resolveInPlace(super.getGenericExceptionTypes());
+ }
+ @Override public TypeToken<T> getOwnerType() {
+ return TypeToken.this;
+ }
+ };
+ }
+
+ /**
+ * 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)
+ .toSet());
+ } 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)
+ .toSet());
+ } 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();
+ }
+ })
+ .toSet();
+ }
+
+ @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)
+ .toSet());
+ } 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<?>: http://goo.gl/YzaEd
+ 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..c19f38e
--- /dev/null
+++ b/guava/src/com/google/common/reflect/Types.java
@@ -0,0 +1,504 @@
+/*
+ * 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);
+ }
+ }
+ }
+
+ /** 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;