【发布时间】:2018-06-07 01:36:33
【问题描述】:
我使用此代码执行 HTTP POST 请求并反序列化返回值:
ParameterizedTypeReference<MyClass> typeRef = new ParameterizedTypeReference<>() {};
HttpEntity<Object> requestEntity = new HttpEntity<>("some text");
ResponseEntity<MyClass> result = restTemplate.exchange("/test", HttpMethod.POST, requestEntity, typeRef);
MyClass returnValue = result.getBody();
为了方便使用,我尝试将代码包装在一个函数中,如下所示:
public <T> T post(Object content, Class<T> returnType, String url){
ParameterizedTypeReference<T> typeRef = new ParameterizedTypeReference<>() {};
HttpEntity<Object> requestEntity = new HttpEntity<>(content);
ResponseEntity<T> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, typeRef);
return response.getBody();
}
但是,代码在放入函数时会停止运行。它抛出java.lang.ClassCastException: java.base/java.util.LinkedHashMap cannot be cast to client.rest.MyClass。似乎某些类型信息在此过程中丢失了。
以下是 2 个测试用例形式的完整代码:
package client.rest;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.support.RestGatewaySupport;
import static org.springframework.test.web.client.ExpectedCount.times;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
class MyClass {
public int getInt(){
return 1;
}
public void setInt(int i){}
}
public class TEMP {
public static RestTemplate restTemplate = new RestTemplate();
public static MockRestServiceServer mockServer;
@BeforeClass
public static void beforeClass() throws JsonProcessingException {
MyClass value = new MyClass();
// set up a mock server
RestGatewaySupport gateway = new RestGatewaySupport();
gateway.setRestTemplate(restTemplate);
mockServer = MockRestServiceServer.bindTo(gateway).build();
ObjectMapper objectmapper = new ObjectMapper();
String payload = objectmapper.writeValueAsString(value);
mockServer.expect(times(2), requestTo("/test"))
.andRespond(withSuccess(payload, MediaType.APPLICATION_JSON));
}
@Test
public void without_function() {
ParameterizedTypeReference<MyClass> typeRef = new ParameterizedTypeReference<>() {};
HttpEntity<Object> requestEntity = new HttpEntity<>("some text");
ResponseEntity<MyClass> result = restTemplate.exchange("/test", HttpMethod.POST, requestEntity, typeRef);
MyClass returnValue = result.getBody();
}
public <T> T post(Object content, Class<T> returnType, String url){
ParameterizedTypeReference<T> typeRef = new ParameterizedTypeReference<>() {};
HttpEntity<Object> requestEntity = new HttpEntity<>(content);
ResponseEntity<T> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, typeRef);
return response.getBody();
}
@Test
public void with_function() {
MyClass returnValue = post("some text", MyClass.class, "/test");
}
}
我的问题有两个:
- 为什么该功能不起作用?
- 我怎样才能让它工作?
【问题讨论】:
-
根据您的异常,您的地图至少有一个元素无法转换为您的类。这就是我们使用泛型的原因,将运行时错误更改为编译时间和类型安全。
-
你从不使用
returnTypeargument。您需要为该类型创建一个 ParameterizedTypeReference。 docs.spring.io/spring/docs/current/javadoc-api/org/… -
@JBNizet 而不是 typeRef 将 returnType 传递给交换方法已经有效,但我想主要问题是;为什么 ParameterizedTypeReference 不能识别泛型。
-
@JBNizet 我不明白。为什么我必须使用
returnType,为什么T不够用?它们几乎是一样的,不是吗?能详细解释一下吗? -
因为泛型类型在 Java 中被删除了。 ParameterizedTypeReference 的全部意义在于通过将其子类化为匿名内部类并实例化它来捕获在创建它时传递的具体泛型类型:
new ParameterizedTypeReference<MyClass>() {}。一旦你使这个通用化,就没有要捕获的具体类了。 T 被编译器擦除为 Object。因此,由于 JSON 解组,Jackson 不再知道它必须使用哪种类型。
标签: java spring function generics jackson