如何将泛型 class 作为方法的泛型参数传递
How to pass generic class as a generic parameter of method
我在将 class 作为方法 f.e 的通用参数传递时遇到问题。我有一个简单的方法:
<T> T sendRequest(SomeRestApiRequest request, Class<T> responseClass)
哪个解析响应指定的表单。我这样使用它们:
ItemListJSON itemList = new ItemListJSON();
itemList = someRestClient.sendRequest(req, ItemListJSON.class);
对于 ItemListJSON.class 看起来像这样:
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"totalSize","items"})
public class ItemListJSON {
@JsonProperty("items")
private List<SalonJSON> items;
@JsonProperty("totalSize")
private int totalSize;
//...getters, setters...
}
一切都很好。但我的问题是:
是否可以将泛型 class 作为 sendRequest 方法的参数传递?
我希望 ItemListJSON class 是通用的,在我的例子中:
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"totalSize","items"})
public class ItemListJSON<T> {
@JsonProperty("items")
private List<T> items;
@JsonProperty("totalSize")
private int totalSize;
//...getters, setters...
}
但是当我尝试以这种方式使用 sendRequest 方法时:
ItemListJSON<SalonJSON> itemList = new ItemListJSON<SalonJSON>();
itemList = someRestClient.sendRequest(req, ItemListJSON.class);
我在 Eclipse 上收到警告 IDE
Type safety: The expression of type ItemListJSON needs unchecked
conversion to conform to ItemListJSON
当调用方法时,我在服务器控制台中遇到错误:
SEVERE: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to xxx.ServiceCategoryJSON] with root cause
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to xxx.ServiceCategoryJSON
@编辑:
我调试了我的 sendRequest 方法,我发现错误发生在 processResponse 方法中,其中 ObjectMapper 将响应映射到对象。
private <T> T processResponse(Response response, Class<T> responseClass) throws ParseException, IOException {
ObjectMapper om = new ObjectMapper();
om.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
return om.readValue(response.getBody(), responseClass); //throw exception
}
使用
ParameterizedTypeReference<ItemListJSON<SalonJSON>> typeRef = new ParameterizedTypeReference<ItemListJSON<SalonJSON>>() {};
中的代码片段
RestTemplate restTemplate = new RestTemplate();
ParameterizedTypeReference<List<String>> listOfString = new ParameterizedTypeReference<List<String>>() {};
ResponseEntity<List<String>> response= restTemplate.exchange(baseUrl,HttpMethod.GET,null, listOfString);
HttpHeaders headers = response.getHeaders();
MediaType contentType = headers.getContentType();
long date = headers.getDate();
List<String> getOrDefault = headers.getOrDefault("X-Forwarded", Collections.singletonList("Does not exists"));
您可以通过传递 com.fasterxml.jackson.core.type.TypeReference
而不是 Class<T>
来做到这一点
public class GenericSerializationTest {
@Data //lombok
public static class ItemListJSON<T> {
private List<T> items;
}
@Data //lombok
public static class StructureExample {
private final String name;
private final Double price;
}
public static class Sender {
private final ObjectMapper objectMapper = new ObjectMapper();
public <T> T sendRequest(String json, TypeReference typeReference) throws IOException {
//sender logic - in this case I assume that json is API response
return objectMapper.readValue(json, typeReference);
}
}
@Test
public void testMethod() throws IOException {
Sender sender = new Sender();
ItemListJSON<StructureExample> test = sender.sendRequest("{\"items\": [{\"name\":\"MacBook Pro\",\"price\":101.345}, {\"name\":\"MacMini\",\"price\":102.345}]}", new TypeReference<ItemListJSON<StructureExample>>() {});
assertEquals("Should contain only 2 items", 2, test.getItems().size());
assertEquals("Name of first item is not correct", "MacBook Pro", test.getItems().get(0).getName());
assertEquals("Name of second item is not correct", "MacMini", test.getItems().get(1).getName());
}
}
我在将 class 作为方法 f.e 的通用参数传递时遇到问题。我有一个简单的方法:
<T> T sendRequest(SomeRestApiRequest request, Class<T> responseClass)
哪个解析响应指定的表单。我这样使用它们:
ItemListJSON itemList = new ItemListJSON();
itemList = someRestClient.sendRequest(req, ItemListJSON.class);
对于 ItemListJSON.class 看起来像这样:
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"totalSize","items"})
public class ItemListJSON {
@JsonProperty("items")
private List<SalonJSON> items;
@JsonProperty("totalSize")
private int totalSize;
//...getters, setters...
}
一切都很好。但我的问题是:
是否可以将泛型 class 作为 sendRequest 方法的参数传递?
我希望 ItemListJSON class 是通用的,在我的例子中:
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"totalSize","items"})
public class ItemListJSON<T> {
@JsonProperty("items")
private List<T> items;
@JsonProperty("totalSize")
private int totalSize;
//...getters, setters...
}
但是当我尝试以这种方式使用 sendRequest 方法时:
ItemListJSON<SalonJSON> itemList = new ItemListJSON<SalonJSON>();
itemList = someRestClient.sendRequest(req, ItemListJSON.class);
我在 Eclipse 上收到警告 IDE
Type safety: The expression of type ItemListJSON needs unchecked conversion to conform to ItemListJSON
当调用方法时,我在服务器控制台中遇到错误:
SEVERE: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to xxx.ServiceCategoryJSON] with root cause
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to xxx.ServiceCategoryJSON
@编辑:
我调试了我的 sendRequest 方法,我发现错误发生在 processResponse 方法中,其中 ObjectMapper 将响应映射到对象。
private <T> T processResponse(Response response, Class<T> responseClass) throws ParseException, IOException {
ObjectMapper om = new ObjectMapper();
om.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
return om.readValue(response.getBody(), responseClass); //throw exception
}
使用
ParameterizedTypeReference<ItemListJSON<SalonJSON>> typeRef = new ParameterizedTypeReference<ItemListJSON<SalonJSON>>() {};
中的代码片段
RestTemplate restTemplate = new RestTemplate();
ParameterizedTypeReference<List<String>> listOfString = new ParameterizedTypeReference<List<String>>() {};
ResponseEntity<List<String>> response= restTemplate.exchange(baseUrl,HttpMethod.GET,null, listOfString);
HttpHeaders headers = response.getHeaders();
MediaType contentType = headers.getContentType();
long date = headers.getDate();
List<String> getOrDefault = headers.getOrDefault("X-Forwarded", Collections.singletonList("Does not exists"));
您可以通过传递 com.fasterxml.jackson.core.type.TypeReference
而不是 Class<T>
public class GenericSerializationTest {
@Data //lombok
public static class ItemListJSON<T> {
private List<T> items;
}
@Data //lombok
public static class StructureExample {
private final String name;
private final Double price;
}
public static class Sender {
private final ObjectMapper objectMapper = new ObjectMapper();
public <T> T sendRequest(String json, TypeReference typeReference) throws IOException {
//sender logic - in this case I assume that json is API response
return objectMapper.readValue(json, typeReference);
}
}
@Test
public void testMethod() throws IOException {
Sender sender = new Sender();
ItemListJSON<StructureExample> test = sender.sendRequest("{\"items\": [{\"name\":\"MacBook Pro\",\"price\":101.345}, {\"name\":\"MacMini\",\"price\":102.345}]}", new TypeReference<ItemListJSON<StructureExample>>() {});
assertEquals("Should contain only 2 items", 2, test.getItems().size());
assertEquals("Name of first item is not correct", "MacBook Pro", test.getItems().get(0).getName());
assertEquals("Name of second item is not correct", "MacMini", test.getItems().get(1).getName());
}
}