user2962698
user2962698

Reputation: 155

Getting MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=text/plain When output is JSON string

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>

Upvotes: 0

Views: 8026

Answers (1)

Denis Abakumov
Denis Abakumov

Reputation: 422

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

Upvotes: 1

Related Questions