浏览 2763 次
锁定老帖子 主题:Guice框架的收集范性的bug
该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2007-04-17
import static com.google.inject.util.Objects.nonNull; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.GenericArrayType; import java.util.ArrayList; import java.util.List; /** * Represents a generic type {@code T}. Java doesn't yet provide a way to * represent generic types, so this class does. Forces clients to create a * subclass of this class which enables retrieval the type information even at * runtime. * * <p>For example, to create a type literal for {@code List<String>}, you can * create an empty anonymous inner class: * * <p> * {@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};} * * <p>Assumes that type {@code T} implements {@link Object#equals} and * {@link Object#hashCode()} as value (as opposed to identity) comparison. * * @author crazybob@google.com (Bob Lee) */ public abstract class TypeLiteral<T> { final Class<? super T> rawType; final Type type; final int hashCode; /** * Constructs a new type literal. Derives represented class from type * parameter. * * <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. */ @SuppressWarnings("unchecked") protected TypeLiteral() { this.type = getSuperclassTypeParameter(getClass()); this.rawType = (Class<? super T>) getRawType(type); this.hashCode = hashCode(type); } /** * Unsafe. Constructs a type literal manually. */ @SuppressWarnings("unchecked") TypeLiteral(Type type) { this.rawType = (Class<? super T>) getRawType(nonNull(type, "type")); this.type = type; this.hashCode = hashCode(type); } /** * Gets type from super class's type parameter. */ static Type getSuperclassTypeParameter(Class<?> subclass) { Type superclass = subclass.getGenericSuperclass(); if (superclass instanceof Class) { throw new RuntimeException("Missing type parameter."); } return ((ParameterizedType) superclass).getActualTypeArguments()[0]; } /** * Gets type literal from super class's type parameter. */ static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) { return new SimpleTypeLiteral<Object>(getSuperclassTypeParameter(subclass)); } @SuppressWarnings({ "unchecked" }) private static Class<?> getRawType(Type type) { if (type instanceof Class<?>) { // type is a normal class. return (Class<?>) type; } else { if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; // I'm not exactly sure why getRawType() returns Type instead of Class. // Neal isn't either but suspects some pathological case related // to nested classes exists. Type rawType = parameterizedType.getRawType(); if (!(rawType instanceof Class<?>)) { throw unexpectedType(rawType, Class.class); } return (Class<?>) rawType; } if (type instanceof GenericArrayType) { // TODO: Is this sufficient? return Object[].class; } System.out.println(type); // type is a parameterized type. throw unexpectedType(type, ParameterizedType.class); } } /** * Gets the raw type. */ Class<? super T> getRawType() { return rawType; } /** * Gets underlying {@code Type} instance. */ public Type getType() { return type; } public int hashCode() { return this.hashCode; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof TypeLiteral<?>)) { return false; } TypeLiteral<?> other = (TypeLiteral<?>) o; return equals(type, other.type); } public String toString() { return type instanceof Class<?> ? ((Class<?>) type).getName() : type.toString(); } static AssertionError unexpectedType(Type type, Class<?> expected) { return new AssertionError( "Unexpected type. Expected: " + expected.getName() + ", got: " + type.getClass().getName() + ", for type literal: " + type.toString() + "."); } /** * Gets type literal for the given {@code Type} instance. */ public static TypeLiteral<?> get(Type type) { return new SimpleTypeLiteral<Object>(type); } public static void main(String args[]) throws Exception { System.out.println(new SimpleTypeLiteral<String>(new SimpleType<String>().getClass().getGenericSuperclass()).getRawType()); System.out.println(new SimpleTypeLiteral<String>(new SimpleType<String>().getClass().getGenericSuperclass()).getType()); } /** * Gets type literal for the given {@code Class} instance. */ public static <T> TypeLiteral<T> get(Class<T> type) { return new SimpleTypeLiteral<T>(type); } private static class SimpleTypeLiteral<T> extends TypeLiteral<T> { public SimpleTypeLiteral(Type type) { super(type); } } private static class SimpleType<T> extends TypeLiteral<T> { } static int hashCode(Type type) { if (type instanceof ParameterizedType) { ParameterizedType p = (ParameterizedType) type; int h = p.getRawType().hashCode(); for (Type argument : p.getActualTypeArguments()) { h = h * 31 + hashCode(argument); } return h; } if (type instanceof Class) { // Class specifies hashCode(). return type.hashCode(); } if (type instanceof GenericArrayType) { return hashCode(((GenericArrayType) type).getGenericComponentType()) * 31; } // This isn't a type we support. Could be a generic array type, wildcard // type, etc. return type.hashCode(); } static boolean equals(Type a, Type b) { if (a instanceof Class) { // Class already specifies equals(). return a.equals(b); } if (a instanceof ParameterizedType) { if (!(b instanceof ParameterizedType)) { return false; } ParameterizedType pa = (ParameterizedType) a; ParameterizedType pb = (ParameterizedType) b; if (!pa.getRawType().equals(pb.getRawType())) { return false; } Type[] aa = pa.getActualTypeArguments(); Type[] ba = pb.getActualTypeArguments(); if (aa.length != ba.length) { return false; } for (int i = 0; i < aa.length; i++) { if (!equals(aa[i], ba[i])) { return false; } } return true; } if (a instanceof GenericArrayType) { if (!(b instanceof GenericArrayType)) { return false; } return equals( ((GenericArrayType) a).getGenericComponentType(), ((GenericArrayType) b).getGenericComponentType() ); } // This isn't a type we support. Could be a generic array type, wildcard // type, etc. return false; } } 以上是Guice源代码 里面利用父类取得T.class, 但是利用extends TypeLiteral<T>是娶不到T.class的 private static class SimpleTypeLiteral<T> extends TypeLiteral<T> { public SimpleTypeLiteral(Type type) { super(type); } } 代码中的 private static class SimpleType<T> extends TypeLiteral<T> { }是我加的内部类为的是模拟运行时状态 这里是测试代码 public static void main(String args[]) throws Exception { System.out.println(new SimpleTypeLiteral<String>(new SimpleType<String>().getClass().getGenericSuperclass()).getRawType()); System.out.println(new SimpleTypeLiteral<String>(new SimpleType<String>().getClass().getGenericSuperclass()).getType()); } new SimpleType<String>().getClass().getGenericSuperclass()可以得到一个范性class, 利用Guice提供的构造方法new SimpleTypeLiteral: 当extends TypeLiteral<T>时,父类TypeLiteral中的T不能正确得到范性,而是=T,爆出以下异常 Exception in thread "main" java.lang.AssertionError: Unexpected type. Expected: java.lang.reflect.ParameterizedType, got: sun.reflect.generics.reflectiveObjects.TypeVariableImpl, for type literal: T. at com.google.inject.TypeLiteral.unexpectedType(TypeLiteral.java:160) at com.google.inject.TypeLiteral.getRawType(TypeLiteral.java:119) at com.google.inject.TypeLiteral.<init>(TypeLiteral.java:61) at com.google.inject.TypeLiteral$SimpleType.<init>(TypeLiteral.java:193) at com.google.inject.TypeLiteral$SimpleType.<init>(TypeLiteral.java:193) at com.google.inject.TypeLiteral.main(TypeLiteral.java:176) 当extends TypeLiteral<String>时,正常 是不是没有方法取得对象的范性? 如上的new SimpleType<String>()中的String? 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |