DWR 如何转换传入数据并规避类型擦除

How DWR cast incoming data and evade type erasure

我想申请 class 项 collection 项(具体反映)。但是关于类型擦除似乎是不可能的,而且关于我在堆栈上阅读过的一些主题。有一些解决方法(here),但我很好奇是否有人知道它是如何完成的,例如 DWR:

http://directwebremoting.org/dwr/documentation/server/configuration/dwrxml/signatures.html

或者,如果有更好的解决方法,那就太好了。

假设我们有类似的东西:

public String foo(List<String> possibleFoos) {

我需要做的就是找出参数 possibleFoos 是字符串列表,而不仅仅是列表

虽然 Java 确实会在运行时擦除类型(从而将 List<String> 变成 List),但在许多情况下,它确实会在运行时存储泛型类型,从而允许您恢复因擦除而丢失的信息。 您可以检索这些的实际通用类型:

  • 方法参数(你的情况)
  • 方法return类型
  • 字段类型
  • 超级classes/interfaces

这意味着,如果您只有一个类型为 List 的对象,您将无法获得它的通用类型(object.getClass() 将获得 List,仅此而已)- 它已永久丢失.但是,如果您试图找出方法参数或上述任何参数的泛型类型,您通常 可以 通过使用反射。由于您的案例不涉及类型变量或其他并发症,因此获取实际类型非常简单:

ParameterizedType listArgument = (ParameterizedType) ClassDeclaringFoo.class.getMethod("foo", List.class).getGenericParameterTypes()[0];
Type listType = listArgument.getActualTypeArguments()[0]; //This will be a Class representing String, the type of the List

如果您有更多参数和地图:

public String foo(Object bar, Map<String, Number> possibleFoos) { ... }

代码类似:

ParameterizedType mapArgument = (ParameterizedType) ClassDeclaringFoo.class.getMethod("foo", Object.class, Map.class).getGenericParameterTypes()[1]; //1 is the index of the map argument
Type keyType = mapArgument.getActualTypeArguments()[0]; //This will be a Class representing String, the type of the Map key
Type valType = mapArgument.getActualTypeArguments()[1]; //This will be a Class representing Number, the type of the Map value

可以安全地假设这也是 DWR 正在使用的,因为类型是方法参数。

类似的方法可用于其他列出的案例:

  • Class.getMethod(...).getGenericReturnType() 会给你真正的 return 类型
  • Class.getField(fieldName).getGenericType() 会得到字段的真实类型
  • Class.getGenericSuperClass()让你成为真正的超模
  • Class.getGenericInterfaces() 将为您提供真正的接口类型

存在允许访问 AnnotatedType(通用类型加上类型用法注释)的等效方法,在 Java 8:

中引入
  • Class.getMethod(...).getAnnotatedParameterTypes()
  • Class.getMethod(...).getAnnotatedReturnType()
  • Class.getField(fieldName).getAnnotatedType()
  • Class.getAnnotatedSuperClass()
  • Class.getAnnotatedInterfaces()

现在,如果您的情况像示例中一样简单,那么这一切都很好。 但是,想象一下如果您的示例如下所示:

public T foo(List<T> possibleFoos) {...}

在这种情况下,getGenericParameterTypes()[0].getActualTypeArguments()[0] 会给你 T,这是毫无用处的。要解决 T 代表什么,您必须查看 class 定义,也许还有超级 classes,同时跟踪每个 [=] 中类型变量的命名方式114=],因为每个名称可能不同。

为了更容易地使用泛型类型反射,您可以使用一个名为 GenTyRef that does the hard work for you, and if you need support for AnnotatedTypes, you can use my fork called GeAnTyRef (both are in Maven Central). They also include a type factory, that allows you to construct instances of (Annotated)Type, which you can not easily do using normal Java API. There's also a handy super type token 实现的很棒的库,它允许您获得 (Annotated)Type 文字。

有了这些,您可以使用 Java 允许的泛型类型来完成所有事情,而无需我上面解释的麻烦:

  • GenericTypeReflector#getExactParameterTypes( ... )
  • GenericTypeReflector#getExactReturnType( ... )
  • GenericTypeReflector#getExactFieldType( ... )
  • GenericTypeReflector#getExactSuperType( ... )

还有更多的操作,比如判断一个 Type 是否是另一个的超类型(类似于 Class#isAssignableFrom 但对于泛型类型),解析特定类型变量等