I have a generic class that is used as a response by all resources in my API
public class TestResponse<T> {
private boolean result;
private int status;
private T data;
// Getters and Setters
}
I have two more classes that are used to instantiate the TestResponse.Data
field from two different resources
public class TestResponseData01 {
private int id;
// Getters and Setters
}
public class TestResponseData02 {
private String message;
// Getters and Setters
}
one resource that returns a response of type TestResponse<TestResponseData01>
and the other TestResponse<TestResponseData02>
In the test class, I have created a method that runs common tests of the responses of all resources, but I would like to return the TestResponse instance so that I can then run specific tests based on the resource I am testing.
private <T> TestResponse<T> commonTest(Response response, Class<T> dataType) {
TestResponse<T> testResponse = response.readEntity(new GenericType<TestResponse<T>>(){});
// ...
}
The problem is that the statement TestResponse<T> testResponse = response.readEntity(new GenericType<TestResponse<T>>(){})
deserializes the response JSON but for the TestResponse.Data
field it instantiates an object of type java.util.LinkedHashMap
How can I execute the readEntity method so that the TestResponse.Data
field is correctly instantiated with TestResponseData01
or TestResponseData02
?
Full code
pom.xml dependecies
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<lombok.version>1.18.30</lombok.version>
<jersey.version>2.25.1</jersey.version>
<junit.version>5.11.2</junit.version>
</properties>
<dependencies>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!-- Jersey -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</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.ext</groupId>
<artifactId>jersey-bean-validation</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- JUnit -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- Jersey Test -->
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
JerseyTest class
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
@TestInstance(Lifecycle.PER_CLASS)
public class Test_GenericType extends JerseyTest {
@NoArgsConstructor
@AllArgsConstructor
@Getter
@ToString
public static class TestResponse<T> {
private boolean result;
private int status;
private T data;
}
@NoArgsConstructor
@AllArgsConstructor
@Getter
@ToString
public static class TestResponseData01 {
private int id;
}
@NoArgsConstructor
@AllArgsConstructor
@Getter
@ToString
public static class TestResponseData02 {
private String message;
}
@Path("testData01")
@Produces(MediaType.APPLICATION_JSON)
public static class TestResponseData01Resource {
@GET
public Response test() {
TestResponseData01 testResponseData01 = new TestResponseData01(1);
TestResponse<TestResponseData01> testResponse = new TestResponse<TestResponseData01>(true, Response.Status.OK.getStatusCode(), testResponseData01);
return Response.status(Response.Status.OK).entity(testResponse).build();
}
}
@Path("testData02")
@Produces(MediaType.APPLICATION_JSON)
public static class TestResponseData02Resource {
@GET
public Response test() {
TestResponseData02 testResponseData02 = new TestResponseData02("a");
TestResponse<TestResponseData02> testResponse = new TestResponse<TestResponseData02>(true, Response.Status.OK.getStatusCode(), testResponseData02);
return Response.status(Response.Status.OK).entity(testResponse).build();
}
}
@Override
protected Application configure() {
return new ResourceConfig(TestResponseData01Resource.class, TestResponseData02Resource.class);
}
@BeforeAll
public void before() throws Exception {
super.setUp();
}
@AfterAll
public void after() throws Exception {
super.tearDown();
}
private <T> TestResponse<T> commonTest(Response response, Class<T> dataType) {
TestResponse<T> testResponse = response.readEntity(new GenericType<TestResponse<T>>(){});
assertTrue(testResponse.isResult());
assertEquals(200, testResponse.getStatus());
return testResponse;
}
@Test
void Test_ResponseData01Resource() {
Response response = target("testData01").request().get();
TestResponse<TestResponseData01> testResponse = commonTest(response, TestResponseData01.class);
TestResponseData01 testData = testResponse.getData();
assertEquals(1, testData.getId());
}
@Test
void Test_ResponseData02Resource() {
Response response = target("testData02").request().get();
TestResponse<TestResponseData02> testResponse = commonTest(response, TestResponseData02.class);
TestResponseData02 testData = testResponse.getData();
assertEquals("a", testData.getMessage());
}
}
First you need an utility class:
class MyParameterizedType implements ParameterizedType {
private final Type rawType;
private final Type[] params;
private MyParameterizedType(Class clz, Class... params) {
this.params = params;
rawType = clz;
}
@Override
public Type[] getActualTypeArguments() {
return params;
}
@Override
public Type getRawType() {
return rawType;
}
@Override
public Type getOwnerType() {
return null;
}
}
Then it is easy new GenericType(new MyParameterizedType(TestResponse.class, dataType))
.