0

I'm trying to call request.getEntity to return a custom type but it looks like it is getting the response as a text/plain instead of JSON which is giving me the below error. I tested the get output by returning a string and I was able to get a json as a string. I'm not sure why this is happening. Perhaps I'm missing some sort of dependency? The get method is generated using https://github.com/mulesoft-labs/raml-java-client-generator.

Exception in thread "main" org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=text/plain, type=class org.mule.example.resource.weatherdata.model.WeatherdataGETResponse, genericType=class org.mule.example.resource.weatherdata.model.WeatherdataGETResponse.
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:232)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:156)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1085)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:853)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:785)
at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:326)
at org.glassfish.jersey.client.InboundJaxrsResponse$1.call(InboundJaxrsResponse.java:111)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:419)
at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:108)
at org.mule.example.resource.weatherdata.Weatherdata.get(Weatherdata.java:52)
at com.test.Run.main(Run.java:16)

--- My Main Method public class Run {

public static void main(String[] args) {
    WeatherdataGETQueryParam param = new WeatherdataGETQueryParam(-121.955236, 37.354108);
    WeatherdataGETHeader header = new WeatherdataGETHeader();
    header.setXMashapeKey("--some key---");
    WeatherdataGETResponse test =  MashapeWeatherAPIClient.create().weatherdata.get(param, header);
    System.out.println(test);


}

}

---My Get command

  public org.mule.example.resource.weatherdata.model.WeatherdataGETResponse get(WeatherdataGETQueryParam queryParameters, WeatherdataGETHeader headers) {
    WebTarget target = this.client.target(getBaseUri());
    if (queryParameters.getLng()!= null) {
        target = target.queryParam("lng", queryParameters.getLng());
    }
    if (queryParameters.getLat()!= null) {
        target = target.queryParam("lat", queryParameters.getLat());
    }
    final javax.ws.rs.client.Invocation.Builder invocationBuilder = target.request(MediaType.APPLICATION_JSON_TYPE);
    if (headers.getXMashapeKey()!= null) {
        invocationBuilder.header("x-mashape-key", headers.getXMashapeKey());
    }
    Response response = invocationBuilder.get();
    if (response.getStatusInfo().getFamily()!= Family.SUCCESSFUL) {
        Response.StatusType statusInfo = response.getStatusInfo();
        throw new MashapeWeatherAPIException(statusInfo.getStatusCode(), statusInfo.getReasonPhrase());
    }
    return response.readEntity(org.mule.example.resource.weatherdata.model.WeatherdataGETResponse.class);

}

My dependencies

<properties>
    <jersey.version>2.17</jersey.version>
</properties>
<dependencies>
    <!--Jersey client-->
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-client</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>${jersey.version}</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-multipart</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>2.4.1</version>
    </dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-moxy</artifactId>
    <version>2.24</version>
</dependency>       

    <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.6</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>
user2962698
  • 115
  • 2
  • 9
  • how does the response look like? – Ahmad Sanie Mar 10 '17 at 15:34
  • It would look like something like this if I returned a String { "query": { "count": 1, "created": "2014-05-03T03:57:53Z", .... } The return is of valid json I've confirmed it using a JSON validator. I can't fit the whole json object in this comment. – user2962698 Mar 10 '17 at 15:37
  • are you sure your dependencies are configured correctly ? - if you are using maven add your xml, if not show what are the added jars – Ahmad Sanie Mar 10 '17 at 15:49
  • Added above ^^ the https://github.com/mulesoft-labs/raml-java-client-generator link in each of the pom files shows my dependencies – user2962698 Mar 10 '17 at 16:09
  • It seems to be a pattern that no one who actually understands MessageBodyReader is willing to speak about it with any parsimony at all. Shameful. – Adrian M. Apr 20 '17 at 22:27

1 Answers1

1

Let's first look at how Jersey JAX-RS will parse a JSON response with a correct Content-Type: application/json. When it gets such a response, it looks for any available implementation of the javax.ws.rs.ext.MessageBodyReader interface which is annotated as:

@Consumes(MediaType.APPLICATION_JSON)

This can be any implementation, but for our example we added MOXyJsonProvider as a dependency to the project:

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-moxy</artifactId>
    <version>${jersey.version}</version>
</dependency>

Next, we want to make it also handle Content-Type: text/plain responses. For this, we inherit our custom response reader from MOXyJsonProvider at the same time annotating it with MediaType.TEXT_PLAIN:

@Provider
@Consumes(MediaType.TEXT_PLAIN)
public class MyCustomResponseReader extends MOXyJsonProvider {

    @Override
    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return genericType.equals(MyCustomClass.class);
    }

    @Override
    public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
            InputStream entityStream) throws IOException, WebApplicationException {
        return super.readFrom(type, genericType, annotations, mediaType, httpHeaders, entityStream);
    }

}

Note that in the overridden readFrom() method all we do is just call super.readFrom() of the parent class MOXyJsonProvider.

Finally, we need to register our custom reader in the instance of javax.ws.rs.client.Client that will be querying our web service:

Client client = ClientBuilder.newBuilder().build().register(MyCustomResponseReader.class);

Now a text/plain response will be parsed like any application/json one.

GitHub

Full solution can be found on GitHub: PlainTextResponseReader

Credits

I based this solution on the information found in the following resources:

Stack Overflow

Other

Denis Abakumov
  • 355
  • 3
  • 11