0

I have implmented the follwing class and implemented a search method get list of Object for the given type of T using a REST call.

    public class AmapiService<T extends Resource> implements RestService<T> {


    @Override
    public List<T> search( MultivaluedMap<String, String> aQueryParams ) {
          MultivaluedMap<String, String> lQueryParams = aQueryParams;
          Client lClient = buildClient();

      WebTarget ltarget = lClient.target( iRestDriver.target( aApiUrl ).getUri() );

      for ( String lKey : lQueryParams.keySet() ) {
         ltarget = ltarget.queryParam( lKey, lQueryParams.getFirst( lKey ) );
      }

      List<T> lObjects = null;

      lObjects = ltarget.request( MediaType.APPLICATION_JSON ).get( new GenericType<List<T>>() {
      } );

      return lObjects;
   }
}

this is how the instance is created for the class and search method call.

AmapiService<RFQDefinition> RFQService =
            new AmapiService<RFQDefinition>();

List<RFQDefinition> qfq = RFQService.search( lQueryParam );

when i run this im getting the following error

May 07, 2018 1:48:14 PM org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor aroundReadFrom
SEVERE: MessageBodyReader not found for media type=application/json, type=interface java.util.List, genericType=java.util.List<T>.

That means the RFQDefinition does not set to the T in the new GenericType<List<T>>().

how can i set the type from the T in the AmapiService<T extends Resource> to new GenericType<List<T>>()

if i define it new GenericType<List<RFQDefinition>>() Instead of T its working

JanithOCoder
  • 271
  • 5
  • 16
  • `GenericType` is a hack to circumvent type erasure by baking the type into the anonymous subclass. If it were possible to infer generic types at runtime, that parameter wouldn't be necessary in the first place. – shmosel May 07 '18 at 18:29

3 Answers3

1

Your use of generics does actually not serve a purpose here.

There's no true generic implementation as your response is based on the parameter you give to the service you consume (.get( new GenericType<List<T>>(){})). The type parameter doesn't help this because the code is being invoked by the jax-rs implementation, which does not go through static linking.

In other words, no code is going to compile and run against your class/method using the parameter:

//this is not a valid use-case:
List<ActualType> res = search(aQueryParams);

A simple translation for this can be: Java generics don't make it into the REST API. You have to statically use the Java type for the model your API is supposed to return (just as you do with new GenericType<List<RFQDefinition>>()).

ernest_k
  • 39,584
  • 5
  • 45
  • 86
  • Is there any other way to pass the type from AmapiService RFQService = new AmapiService(); ? – JanithOCoder May 07 '18 at 18:36
  • @JanithOCoder How do your service consumers tell you the type that they expect for list elements in the response? That would be the best place to start. – ernest_k May 07 '18 at 18:38
  • can we pass RFQDefinition.class as argument AmapiService RFQService = new AmapiService(RFQDefinition.class) set it to the response? – JanithOCoder May 07 '18 at 18:45
  • @JanithOCoder I still don't see how that would work, unless you get the raw response from your service (such as the raw json string or binary), and do json mapping in this method to that class by yourself. If you use jackson for that, you can use the javatype constructs. Check https://stackoverflow.com/questions/6846244/jackson-and-generic-type-reference – ernest_k May 07 '18 at 18:52
0

It's not related to generic.

The server complains that it does not have any MessageBodyReader to read the application/json body.

Normally, you can add Jackson as json decode/encode for your application

Read this:

https://jersey.github.io/documentation/latest/media.html#json.jackson

Mạnh Quyết Nguyễn
  • 15,590
  • 1
  • 17
  • 41
0

I have changed the Search method Implementation like this, now it is working. iClass you can take this as a parameter eg: RFQDefinition.class

ObjectMapper mapper = new ObjectMapper();
      JavaType type = mapper.getTypeFactory().constructCollectionType( List.class, iClass );
      List<T> lObjects = null;

      JsonArray lResponse = ltarget.request( MediaType.APPLICATION_JSON ).get( JsonArray.class );
      try {
         lObjects = mapper.readValue( lResponse.toString(), type );
      } catch ( JsonParseException e ) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch ( JsonMappingException e ) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch ( IOException e ) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }  
JanithOCoder
  • 271
  • 5
  • 16