2011-08-12 17 views
16

Estoy tratando de escribir una función genérica en Jersey que se puede usar para buscar una Lista de objetos del mismo tipo a través de REST. Me basé en las informaciones que se encuentran en este foro: linkObteniendo recurso REST como List <T> con 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>>() {}); 
} 

Sin embargo esto no está funcionando. Si intento ejecutarlo, aparece el siguiente error: 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.

Sin embargo, si escribo esta función sin plantillas (reemplazando T con un nombre de clase real) simplemente funciona bien. Por supuesto, de esta manera la función pierde su significado.

¿Hay alguna manera de arreglar esto?

+0

Consulte a continuación enlace http://stackoverflow.com/questions/1603404/using-jaxb-to-unmarshal-marshal-a-liststring – fmucar

+0

@fmucar: esto de nuevo tiene consejos para el servidor como Ya veo. Necesito soporte de tipo genérico para el cliente. – NagyI

Respuesta

21

que he encontrado la solución 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

Esto me funcionó con Jersey 2.9, ¡muchas gracias! –

+0

BTW, se extendió en su ejemplo y utilizó la clase de base Collection.class para OwnerType y RawType y esto funcionó también. Así que debería ser capaz de reutilizar el único parameterType para todos los tipos de colección. –

6

clase Ver GenericType de la camiseta que puede ayudar también

Unmarshaller necesita saber qué tipo es el objeto que hay antes de que pueda unmarhall el contenido devuelto. Como la información genérica no está disponible en tiempo de ejecución, entonces lo que está preguntando no es posible. No se puede desmarcar algo de lo que no se sabe nada.

Lo mejor que puedes hacer es;

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

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

o con los genéricos advertencias (no estoy seguro de si esto va a funcionar)

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

Ha proporcionado una muestra para el lado del servidor. ¿Cómo puede ayudarme esto en el lado del cliente? Puedo ver la lista generada por el servidor de Jersey en el navegador. Mi problema es que el cliente no puede recuperar el recurso si estoy usando Type genérico en la función anterior. Puedo buscar el recurso si construyo el cliente manualmente cada vez que estoy en el lugar para un tipo específico. Sin embargo, no quiero esto. – NagyI

+0

Bien, tengo. Es el mismo problema que se describe aquí: http://janmaterne.wordpress.com/2008/10/10/getting-the-type-of-a-generic-class-at-runtime/ – NagyI

+0

¿Puedo preguntar por qué la información genérica no está disponible? ¿Está disponible durante el tiempo de ejecución? – gosua

3

Extendiéndose sobre user2323189, puede utilizar Colección en lugar de List.class para que pueda serializar todos los tipos que extienden Collection. Creo un getter simple en mi clase de cliente base y simplemente puedo usar esto para recuperar cualquier tipo de colección. No se proporciona la variable clazz proporcionada en mi constructor, por lo que no es un argumento proporcionado. Probablemente puedas convertir esto en un método estático y usar la firma GenericType> con un parámetro para Class para hacerlo aún más genérico.

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){}; 
    } 
Cuestiones relacionadas