I am trying to test a Jax-rs resource by following this https://jersey.java.net/documentation/latest/test-framework.html,
and I am using container jersey-test-framework-provider-jdk-http
I can assert status code. However, when I try to readEntity, I get exception:
javax.ws.rs.ProcessingException: Unable to find a MessageBodyReader of content-type application/json and type class java.lang.String
at org.jboss.resteasy.core.interception.ClientReaderInterceptorContext.throwReaderNotFound(ClientReaderInterceptorContext.java:39)
at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.getReader(AbstractReaderInterceptorContext.java:73)
at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.proceed(AbstractReaderInterceptorContext.java:50)
at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readFrom(ClientResponse.java:248)
at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readEntity(ClientResponse.java:181)
at org.jboss.resteasy.specimpl.BuiltResponse.readEntity(BuiltResponse.java:217)
My Resource Class:
@Path("/")
public class SampleResource {
@GET
@Path("/health")
@Produces(MediaType.APPLICATION_JSON)
public String getServiceStatus() {
return "{\"Status\": \"OK\"}";
}
}
My Test Class:
public class TestSampleResource extends JerseyTest {
@Override
protected Application configure() {
return new ResourceConfig(SampleResource.class);
}
@Test
public void testHealthEndpoint() {
Response healthResponse = target("health").request(MediaType.APPLICATION_JSON).get();
Assert.assertEquals(200, healthResponse.getstatus()); // works
String body = healthResponse.readEntity(String.class);
Assert.assertEquals("{\"Status\": \"OK\"}", body);
}
}
Can anyone please help?
The problem comes from having both Jersey and RestEasy client on the classpath. When you call target()
on the JerseyTest
, the WebTarget
is obtained from a Client
that is built by calling ClientBuilder.newClient()
.
The ClientBuilder
is a standard JAX-RS API, and it is implemented first to search for an implementation of ClientBuilder
through the META-INF/services
files, looking for a file named javax.ws.rs.client.ClientBuilder
, whose content is the name of an implementation of the ClientBuilder
. If no such file is found, it defaults to looking for JerseyClientBuilder
.
jersey-client
has no such file META-INF/services/javax.ws.rs.core.ClientBuilder
because it's ClientBuilder
is the default for JAX-RS client. If you look in your resteasy-client
jar, you will see the it does have that file. And if you look in the contents of that file, you will see the ResteasyClientBuilder
as the implementation.
So even though you are using Jersey's test framework, the Client
being used, is RESTeasy's implementation. And I guess all the standard configurations with entity providers never gets configured. Conversion between String and application/json is one of those standard providers you need in your case.
I would say just explicitly use Jersey client implementation. You will no longer be able to call target
on the JerseyTest
. You will need to explicitly create the client
@Test
public void dotest() {
final Client client = new JerseyClientBuilder().build();
WebTarget target = client.target("http://localhost:9998");
final Response response = target.path("health").request().get();
final String json = response.readEntity(String.class);
}
The default base path for JerseyTest
is http://localhost:9998
, so I explicitly create the WebTarget
with that.
Note that I said the String
to/from application/json
is supported by standard providers. So if you will only be serializing Strings, then you don't need anything else. If you want POJO serialization support for the Jersey client (and server side), you should add the following
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>
I suspect the json parser in your test is being misguided by the presence of curly braces. Basically it thinks you are returning a json object, not a json string. Try returning "Status:OK"
As the exception says you are missing a MessageBodyReader for content-type application/json
. Do you have JacksonJsonProvider on your classpath? It can be added as a dependency to jackson-jaxrs-json-provider
:
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.7.3</version>
</dependency>
Then register the JacksonJsonProvider in your test application:
@Override
protected Application configure() {
return new ResourceConfig(SampleResource.class, JacksonJsonProvider.class);
}