论坛首页 入门技术论坛

Guice框架的收集范性的bug

浏览 2763 次
该帖已经被评为新手帖
作者 正文
   发表时间:2007-04-17  
package com.google.inject;

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?


论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics