2011-08-12 13 views
16

Próbuję napisać ogólną funkcję w Jersey, która może być używana do pobierania listy obiektów tego samego typu poprzez REST. Oparłem się na informacjach znalezionych na tym forum: linkPobieranie zasobu REST jako listy <T> z Jersey

@Override 
public <T> List<T> fetchResourceAsList(String url) { 
    ClientConfig cc = new DefaultClientConfig(); 
    Client c = Client.create(cc); 
    if (userName!=null && password!=null) { 
    c.addFilter(new HTTPBasicAuthFilter(userName, password)); 
    } 
    WebResource resource = c.resource(url); 
    return resource.get(new GenericType<List<T>>() {}); 
} 

Jednak to nie działa. Jeśli spróbuję go wykonać, pojawia się następujący błąd: SEVERE: A message body reader for Java class java.util.List, and Java type java.util.List<T>, and MIME media type application/xml was not found.

Jednak jeśli piszę tę funkcję bez szablonów (zastępując T rzeczywistą nazwą klasy), to po prostu działa dobrze. Oczywiście w ten sposób funkcja traci sens.

Czy istnieje sposób, aby to naprawić?

+0

Patrz niżej linkiem http://stackoverflow.com/questions/1603404/using-jaxb-to-unmarshal-marshal-a-liststring – fmucar

+0

@fmucar: to znowu ma wskazówek na serwerze jako Widzę. Potrzebuję ogólnego wsparcia typu dla klienta. – NagyI

Odpowiedz

21

Znalazłem rozwiązanie https://java.net/projects/jersey/lists/users/archive/2011-08/message/37

public <T> List<T> getAll(final Class<T> clazz) { 

    ParameterizedType parameterizedGenericType = new ParameterizedType() { 
     public Type[] getActualTypeArguments() { 
      return new Type[] { clazz }; 
     } 

     public Type getRawType() { 
      return List.class; 
     } 

     public Type getOwnerType() { 
      return List.class; 
     } 
    }; 

    GenericType<List<T>> genericType = new GenericType<List<T>>(
      parameterizedGenericType) { 
    }; 

    return service.path(Path.ROOT).path(clazz.getSimpleName()) 
      .accept(MediaType.APPLICATION_XML).get(genericType); 
} 
+0

To działało na mnie z Jersey 2.9, dziękuję bardzo !! –

+0

BTW, Rozszerzony na twoim przykładzie i użył podstawowej klasy Collection.class dla OwnerType i RawType i to działało również. Powinienem móc ponownie użyć parametru parameterizedType dla wszystkich typów kolekcji. –

6

See GenericType klasa Jersey, która może pomóc także

Unmarshaller musi wiedzieć, jaki rodzaj obiektu istnieje zanim unmarhall wracającą treści. Ponieważ informacje generyczne nie są dostępne w czasie wykonywania, więc to, o co prosisz, nie jest możliwe. Nie może oszukiwać czegoś, o czym nic nie wie.

najlepiej można zrobić;

public <T> List<T> fetchResourceAsList(Class<?> beanClass, String url) { 
    ... 

    if(beanCLass.equals(MyBean.class)){ 
     return resource.get(new GenericType<List<MyBean>>() 
    }else if(...){ 
     ... 
    }... 
} 

lub z rodzajowych ostrzeżeń (nie jestem pewien, czy to będzie działać)

public List fetchResourceAsList(String url) { 
    ... 
     return resource.get(new GenericType<List<Serializable>>() 
} 
+0

Podałeś próbkę po stronie serwera. Jak to może mi pomóc po stronie klienta? Mogę wyświetlić listę wygenerowaną przez serwer Jersey w przeglądarce. Mój problem polega na tym, że klient nie może pobrać zasobu, jeśli używam rodzaju ogólnego w powyższej funkcji. Mogę pobrać zasób jeśli ręcznie skonstruuję klienta za każdym razem na miejscu dla określonego typu. Jednak nie chcę tego. – NagyI

+0

OK, mam. Jest to ten sam problem opisany tutaj: http://janmaterne.wordpress.com/2008/10/10/getting-the-type-of-a-eneric-class-at-runtime/ – NagyI

+0

Czy mogę zapytać, dlaczego informacje ogólne nie są jest dostępne w czasie wykonywania? – gosua

3

Rozszerzenie na user2323189, można użyć Collection zamiast List.class, aby móc serializować wszystkie typy rozszerzające kolekcję. Tworzę prosty getter w mojej podstawowej klasie klienta i mogę go po prostu użyć do pobrania dowolnego typu kolekcji. Nie dostarczana jest zmienna clazz w moim konstruktorze, więc nie jest to argument dostarczony. Prawdopodobnie możesz przekształcić to w statyczną metodę i użyć podpisu GenericType> z parametrem dla klasy, aby uczynić go jeszcze bardziej ogólnym.

public GenericType<Collection<T>> getParameterizedCollectionType() { 
     ParameterizedType parameterizedGenericType = new ParameterizedType() { 
      public Type[] getActualTypeArguments() { 
       return new Type[] { clazz }; 
      } 

      public Type getRawType() { 
       return Collection.class; 
      } 

      public Type getOwnerType() { 
       return Collection.class; 
      } 
     }; 
     return new GenericType<Collection<T>>(parameterizedGenericType){}; 
    } 
Powiązane problemy