2016-10-14 7 views
5

Chciałbym poprosić o klasę kolekcji przedmiotów (rodzaj konkretnej refleksji). Ale jeśli chodzi o typ wymazania, wydaje się to niemożliwe, a także w odniesieniu do niektórych tematów, które przeczytałem tutaj na stosie. Istnieją pewne obejścia (here), ale jestem ciekawy, czy ktoś wie, jak to się robi na przykład przez DWR:Jak DWR przesyła dane przychodzące i wymyka się typowi danych

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

lub w przypadku, gdy istnieje jakiś lepszy Rozwiązaniem byłoby wspaniale.

Powiedzmy, że mamy coś takiego:

public String foo(List<String> possibleFoos) { 

i wszystko muszę się dowiedzieć, że possibleFoos parametr jest listą ciągów, nie tylko Lista

Odpowiedz

6

Chociaż prawdą jest, że Java usunie typy na runtime (zmieniając w ten sposób List<String> w tylko List), w wielu przypadkach rzeczywiście przechowuje typ ogólny w środowisku wykonawczym, umożliwiając przywrócenie utraconych informacji w celu ich usunięcia. można pobrać aktualne typy generyczne do nich:

  • argumenty metody (danym przypadku)
  • rodzajów powrotne Metoda
  • typy pól
  • Super klas/interfejsów

Oznacza to, jeśli po prostu masz obiekt typu List, nic nie możesz zrobić, aby uzyskać jego ogólny typ (object.getClass() dostaniesz List i to wszystko) - to był pe ricanently lost. Ale jeśli próbujesz ustalić typowy typ argumentu metody lub którykolwiek z powyższych, zwykle można uzyskać można za pomocą odbicia. Jak twoim przypadku nie wiąże zmienne typu lub inne komplikacje, to całkiem proste, aby uzyskać rzeczywisty typ:

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 

jeśli miał więcej parametrów i mapę Zamiast:

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

kodu, który być podobne:

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 

Można założyć, że jest to również metoda DWR, ponieważ typy są argumentami metod.są

podobne metody dostępne dla innych wymienionych przypadkach:

  • Class.getMethod(...).getGenericReturnType() będzie Ci typ realny zwrot
  • Class.getField(fieldName).getGenericType() będzie Ci prawdziwy typ pola
  • Class.getGenericSuperClass() będzie Ci prawdziwą Super wpisz
  • Class.getGenericInterfaces() otrzymasz prawdziwe typy interfejsów

Odpowiednie metody istnieją umożliwiając dostęp do AnnotatedType (typ ogólny Plus adnotacje na wykorzystaniu typu) wprowadzony w Java 8:

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

Teraz wszystko jest eleganckie, gdy sprawa jest tak prosta jak w przykładzie. Ale wyobraźcie sobie, że Twój przykład wygląda tak:

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

W tym przypadku getGenericParameterTypes()[0].getActualTypeArguments()[0] nie daje T co jest raczej bezużyteczne. Aby rozwiązać to, co oznacza T, trzeba zajrzeć do definicji klasy i być może superklas, jednocześnie śledząc, w jaki sposób zmienne typu są nazywane w każdej klasie, ponieważ nazwy mogą być różne w każdym z nich.

Aby pracować z uniwersalnym typem refleksji łatwiejsze, można użyć wspaniała biblioteka nazywa GenTyRef że wykonuje pracę dla Ciebie, a jeśli potrzebujesz wsparcia dla AnnotatedType s, można użyć mój widelec nazywa GeAnTyRef (oba są w Maven Centralny). Obejmują one również fabrykę typów, która umożliwia konstruowanie instancji o numerze (Annotated)Type, której nie można łatwo wykonać przy użyciu zwykłego interfejsu API języka Java. Jest też poręczna implementacja super type token, która pozwala uzyskać literalny kod (Annotated)Type.

z tymi, można zrobić wszystko z typów generycznych, że Java pozwala bez kłopotów wyjaśniłem powyżej:

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

I wiele innych operacji, takich jak figuri ng out, jeśli jeden Type jest supertypem innego (podobnego do Class#isAssignableFrom, ale dla typów ogólnych), rozróżniając zmienne określonego typu itp.

+0

Dziękuję za wyczerpującą odpowiedź, dokładnie to chciałem wiedzieć! – Radim

+0

Użyłem wersji "kłopotliwej" i działa ona dobrze dla listy, ale nie działa dla mapy, ponieważ getParameterizedType zwraca obiekt klasy.Ponieważ mam lepszy wgląd w twój poprzedni post, próbowałem ponownie szukać sposobu działania z mapą, ale niczego nie znalazłem. Czy możesz mi jeszcze raz pomóc? – Radim

+1

@Radim Zaktualizowałem swoją odpowiedź, aby dołączyć przykład, który ma Mapę jako drugi argument. Czy tego właśnie szukasz? – kaqqao

Powiązane problemy