blob: 932950dff70c501e0c23005e97a253af1821320e [file] [log] [blame]
crazyboblee41bc8522006-12-08 07:06:55 +00001/**
2 * Copyright (C) 2006 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.inject;
18
kevinb9ncad2c2b2007-05-15 17:28:03 +000019import static com.google.inject.internal.Objects.nonNull;
limpbizkiteab76472008-05-26 19:45:12 +000020import com.google.inject.internal.Types;
limpbizkitf530b252008-05-27 23:03:42 +000021import static com.google.inject.internal.Types.canonicalize;
limpbizkite4647a62008-05-25 18:03:35 +000022
23import java.io.Serializable;
crazyboblee41bc8522006-12-08 07:06:55 +000024import java.lang.reflect.ParameterizedType;
kevinb9na99dca72007-02-11 04:48:57 +000025import java.lang.reflect.Type;
crazyboblee41bc8522006-12-08 07:06:55 +000026
27/**
crazyboblee235d0682007-01-31 02:25:21 +000028 * Represents a generic type {@code T}. Java doesn't yet provide a way to
crazybobleee3adfd62007-02-02 21:30:08 +000029 * represent generic types, so this class does. Forces clients to create a
kevinb9na99dca72007-02-11 04:48:57 +000030 * subclass of this class which enables retrieval the type information even at
31 * runtime.
crazybobleee3adfd62007-02-02 21:30:08 +000032 *
kevinb9na99dca72007-02-11 04:48:57 +000033 * <p>For example, to create a type literal for {@code List<String>}, you can
34 * create an empty anonymous inner class:
crazybobleee3adfd62007-02-02 21:30:08 +000035 *
kevinb9na99dca72007-02-11 04:48:57 +000036 * <p>
37 * {@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};}
crazyboblee41bc8522006-12-08 07:06:55 +000038 *
kevinb9na99dca72007-02-11 04:48:57 +000039 * <p>Assumes that type {@code T} implements {@link Object#equals} and
40 * {@link Object#hashCode()} as value (as opposed to identity) comparison.
crazyboblee41bc8522006-12-08 07:06:55 +000041 *
42 * @author crazybob@google.com (Bob Lee)
43 */
limpbizkiteab76472008-05-26 19:45:12 +000044public class TypeLiteral<T> implements Serializable {
crazyboblee41bc8522006-12-08 07:06:55 +000045
46 final Class<? super T> rawType;
47 final Type type;
crazyboblee1b54d6a2007-02-17 02:48:45 +000048 final int hashCode;
crazyboblee41bc8522006-12-08 07:06:55 +000049
50 /**
crazyboblee0baa9fc2007-01-31 02:38:54 +000051 * Constructs a new type literal. Derives represented class from type
crazyboblee41bc8522006-12-08 07:06:55 +000052 * parameter.
53 *
54 * <p>Clients create an empty anonymous subclass. Doing so embeds the type
kevinb9na99dca72007-02-11 04:48:57 +000055 * parameter in the anonymous class's type hierarchy so we can reconstitute it
56 * at runtime despite erasure.
crazyboblee41bc8522006-12-08 07:06:55 +000057 */
kevinb9na99dca72007-02-11 04:48:57 +000058 @SuppressWarnings("unchecked")
crazyboblee0baa9fc2007-01-31 02:38:54 +000059 protected TypeLiteral() {
crazyboblee41bc8522006-12-08 07:06:55 +000060 this.type = getSuperclassTypeParameter(getClass());
limpbizkiteab76472008-05-26 19:45:12 +000061 this.rawType = (Class<? super T>) Types.getRawType(type);
62 this.hashCode = Types.hashCode(type);
crazyboblee41bc8522006-12-08 07:06:55 +000063 }
64
65 /**
crazyboblee0baa9fc2007-01-31 02:38:54 +000066 * Unsafe. Constructs a type literal manually.
crazyboblee41bc8522006-12-08 07:06:55 +000067 */
kevinb9na99dca72007-02-11 04:48:57 +000068 @SuppressWarnings("unchecked")
crazyboblee1b54d6a2007-02-17 02:48:45 +000069 TypeLiteral(Type type) {
limpbizkitf530b252008-05-27 23:03:42 +000070 this.type = canonicalize(nonNull(type, "type"));
71 this.rawType = (Class<? super T>) Types.getRawType(this.type);
72 this.hashCode = Types.hashCode(this.type);
crazyboblee41bc8522006-12-08 07:06:55 +000073 }
74
75 /**
limpbizkitf530b252008-05-27 23:03:42 +000076 * Returns the type from super class's type parameter in {@link
77 * Types#canonicalize(Type) canonical form}.
crazyboblee41bc8522006-12-08 07:06:55 +000078 */
79 static Type getSuperclassTypeParameter(Class<?> subclass) {
80 Type superclass = subclass.getGenericSuperclass();
81 if (superclass instanceof Class) {
82 throw new RuntimeException("Missing type parameter.");
83 }
limpbizkitf530b252008-05-27 23:03:42 +000084 ParameterizedType parameterized = (ParameterizedType) superclass;
85 return canonicalize(parameterized.getActualTypeArguments()[0]);
crazyboblee41bc8522006-12-08 07:06:55 +000086 }
87
88 /**
crazyboblee0baa9fc2007-01-31 02:38:54 +000089 * Gets type literal from super class's type parameter.
crazyboblee41bc8522006-12-08 07:06:55 +000090 */
crazyboblee0baa9fc2007-01-31 02:38:54 +000091 static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) {
limpbizkiteab76472008-05-26 19:45:12 +000092 return new TypeLiteral<Object>(getSuperclassTypeParameter(subclass));
crazyboblee41bc8522006-12-08 07:06:55 +000093 }
94
95 /**
96 * Gets the raw type.
97 */
limpbizkiteab76472008-05-26 19:45:12 +000098 final Class<? super T> getRawType() {
crazyboblee41bc8522006-12-08 07:06:55 +000099 return rawType;
100 }
101
102 /**
103 * Gets underlying {@code Type} instance.
104 */
limpbizkiteab76472008-05-26 19:45:12 +0000105 public final Type getType() {
crazyboblee41bc8522006-12-08 07:06:55 +0000106 return type;
107 }
108
crazyboblee552472f2007-09-07 16:52:39 +0000109 /**
110 * Gets the type of this type's provider.
111 */
112 @SuppressWarnings("unchecked")
limpbizkiteab76472008-05-26 19:45:12 +0000113 final TypeLiteral<Provider<T>> providerType() {
crazyboblee552472f2007-09-07 16:52:39 +0000114 // This cast is safe and wouldn't generate a warning if Type had a type
115 // parameter.
limpbizkite4647a62008-05-25 18:03:35 +0000116 return (TypeLiteral<Provider<T>>) get(
limpbizkiteab76472008-05-26 19:45:12 +0000117 Types.newTypeWithArgument(Provider.class, getType()));
crazyboblee552472f2007-09-07 16:52:39 +0000118 }
119
limpbizkiteab76472008-05-26 19:45:12 +0000120 @Override public final int hashCode() {
crazyboblee1b54d6a2007-02-17 02:48:45 +0000121 return this.hashCode;
crazyboblee41bc8522006-12-08 07:06:55 +0000122 }
123
limpbizkiteab76472008-05-26 19:45:12 +0000124 @Override public final boolean equals(Object o) {
125 return o instanceof TypeLiteral<?>
126 && Types.equals(type, ((TypeLiteral) o).type);
crazyboblee41bc8522006-12-08 07:06:55 +0000127 }
128
limpbizkiteab76472008-05-26 19:45:12 +0000129 @Override public final String toString() {
130 return Types.toString(type);
crazyboblee41bc8522006-12-08 07:06:55 +0000131 }
132
133 /**
crazyboblee0baa9fc2007-01-31 02:38:54 +0000134 * Gets type literal for the given {@code Type} instance.
crazyboblee41bc8522006-12-08 07:06:55 +0000135 */
crazyboblee0baa9fc2007-01-31 02:38:54 +0000136 public static TypeLiteral<?> get(Type type) {
limpbizkiteab76472008-05-26 19:45:12 +0000137 return new TypeLiteral<Object>(type);
crazyboblee41bc8522006-12-08 07:06:55 +0000138 }
139
140 /**
crazyboblee0baa9fc2007-01-31 02:38:54 +0000141 * Gets type literal for the given {@code Class} instance.
crazyboblee41bc8522006-12-08 07:06:55 +0000142 */
crazyboblee0baa9fc2007-01-31 02:38:54 +0000143 public static <T> TypeLiteral<T> get(Class<T> type) {
limpbizkiteab76472008-05-26 19:45:12 +0000144 return new TypeLiteral<T>(type);
crazyboblee41bc8522006-12-08 07:06:55 +0000145 }
146
limpbizkitf530b252008-05-27 23:03:42 +0000147 /**
148 * Returns the canonical form of this type literal for serialization. The
149 * returned instance is always a {@code TypeLiteral}, never a subclass. This
150 * prevents problems caused by serializing anonymous types.
151 */
limpbizkiteab76472008-05-26 19:45:12 +0000152 protected final Object writeReplace() {
limpbizkitf530b252008-05-27 23:03:42 +0000153 return getClass() == TypeLiteral.class
154 ? this
155 : get(type);
crazyboblee1b54d6a2007-02-17 02:48:45 +0000156 }
limpbizkite4647a62008-05-25 18:03:35 +0000157
158 private static final long serialVersionUID = 0;
crazyboblee41bc8522006-12-08 07:06:55 +0000159}