How DWR passes incoming data and avoids type erasure

I would like to request a collection item class (kind of specific reflection). But with regard to type erasure, this seems impossible, as well as with respect to some of the topics that I read here on the stack. There are some workarounds ( here ), but I'm curious if anyone knows how to do this, like DWR:

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

or in case there is some better workaround, that would be great.

Say we have something like:

public String foo(List<String> possibleFoos) { 

and all i need is to find out that the possibleFoos parameter is a list of strings, not just List

+3
source share
1 answer

While it is true that Java erases types at runtime (thus turning List<String> into just List ), in many cases it actually preserves the generic type at runtime, allowing you to recover lost information for deletion. You can get the actual generic types for them:

  • method arguments (your case)
  • Return methods
  • Field types
  • Superclasses / Interfaces

This means that if you just have an object of type List, you can’t do anything to get its generic type ( object.getClass() will get you List and that it) - it was completely lost. But, if you are trying to figure out the general type of argument to a method or any of the above, you can usually use reflection. Since your case does not include type variables or other complications, it is quite simple to get the actual type:

 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 

If instead you had more options and a map:

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

The code will look like:

 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 

We can safely assume that this is what DWR uses, and types are arguments to the method.

Similar methods are available for the other cases listed:

  • Class.getMethod(...).getGenericReturnType() you will get a real return type
  • Class.getField(fieldName).getGenericType() will provide you with a real field type
  • Class.getGenericSuperClass() will give you a real super type
  • Class.getGenericInterfaces() will provide you with real interface types

There are equivalent methods for accessing AnnotatedType (generic type plus usage type annotations) introduced in Java 8:

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

Now, it's all dandy when your case is simple, as in the example. But imagine if your example would look like this:

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

In this case, getGenericParameterTypes()[0].getActualTypeArguments()[0] will give you T , which is useless. To decide what T means, you will need to study the definition of the class and possibly the superclasses, keeping track of how the variable names are indicated in each class, since the names can be different in each.

To make it easier to work with type-type descriptions, you can use a wonderful library called GenTyRef that does the hard work for you, and if you need AnnotatedType s support, you can use my fork called GeAnTyRef (both located in Maven Central). They also include a factory type that allows you to create (Annotated)Type instances that you cannot easily make using the regular Java API. It also has a handy supertext mark that allows you to get a literal (Annotated)Type .

With these functions, you can do everything with the generic types that Java allows without the problems I mentioned above:

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

And many more operations, for example, finding out whether one Type super-type of another (similar to Class#isAssignableFrom , but for general types), allowing certain types of variables, etc.

+6
source

Source: https://habr.com/ru/post/1258199/


All Articles