2016-10-14 8 views
5

Я хотел бы запросить класс предметов (тип конкретного отражения). Но в отношении стирания типа это кажется невозможным, а также в отношении некоторых тем, которые я читал здесь, в стеке. Есть некоторые обходные пути (here), но мне интересно, если кто-нибудь знает, как это делается, например, DWR:Как DWR выдаёт входящие данные и стирает стирание типа

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

или в случае, если есть какой-то обходной путь лучше было бы здорово.

Допустим, у нас есть что-то вроде:

public String foo(List<String> possibleFoos) { 

и все, что мне нужно, чтобы это выяснить, что possibleFoos параметр является список строк, а не просто список

ответ

6

Хотя это правда, что Java сотрет типов в (таким образом, превращая List<String> в List), во многих случаях он фактически сохраняет общий тип во время выполнения, позволяя восстановить потерянную информацию для стирания. Вы можете получить фактические общие типы для них:

  • Метод аргументы (ваш случай)
  • возвращаемых типов Метода
  • типов полей
  • классов/интерфейсы

Это означает, что если у вас просто есть объект типа List, вы ничего не можете сделать, чтобы получить его общий тип (object.getClass() доставит вам List и все) - это было pe rmanually потерял. Но, если вы пытаетесь выяснить общий тип аргумента метода или любой из вышеперечисленных, вы обычно используете , используя. В вашем случае не включает в себя переменные типа или другие осложнения, это довольно просто, чтобы получить фактический тип:

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() поможет вам реального типа возвращаемого
  • 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, вам нужно будет изучить определение класса и, возможно, суперклассы, при этом отслеживая, как переменные типа называются в каждом классе, поскольку имена могут быть разными в каждом.

Для того, чтобы работать с общим типом отражением проще, вы можете использовать прекрасную библиотека называется GenTyRef, что делает тяжелую работу за вас, и если вам нужна поддержка для AnnotatedType с, вы можете использовать мою вилка называется GeAnTyRef (оба в Maven Центральный). Они также включают фабрику типов, которая позволяет создавать экземпляры (Annotated)Type, которые вы не можете легко сделать с помощью обычного Java API. Существует также удобная реализация super type token, позволяющая получить литерал (Annotated)Type.

С теми, что вы можете сделать все с общими типами, что Java позволяет без хлопот я объяснил выше:

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

И еще много операций, таких как figuri ng out, если один Type является супертипом другого (аналогично Class#isAssignableFrom, но для общих типов), разрешая переменные типа и т. д.

+0

Благодарим вас за подробный ответ, именно это я и хотел знать! – Radim

+0

Я использовал версию «hassle», и она отлично работает для списка, но она не работает для карты, потому что getParameterizedType возвращает объект класса.Поскольку у меня есть лучшее представление о вашем предыдущем посту, я попытался снова найти, как действовать с картой, но я ничего не нашел. Можете ли вы мне еще раз помочь? – Radim

+1

@Radim Я обновил свой ответ, чтобы включить пример, в котором в качестве второго аргумента есть карта . Это то, что вам нужно? – kaqqao