前言:
重要,RestTemplate在SpringBoot項目里即便通過HttpMessageConverters添加了Fastjson且優先級比jackson要高也不會在RestTemplate里生效
,換句話說RestTemplate如果要使用Fastjson還是要對RestTemplate進行額外配置,而不是在SpringBoot項目里配置了類型是HttpMessageConverters的Bean就可以了;
方式可以參考:https://www.jianshu.com/p/c9644755dd5e
一:沒有泛型的情況(這里以POST舉例,但是對於GET也是一樣的)
CommonResponse response = restTemplate.postForObject(remoteUrl, tokenRequest, CommonResponse.class);
這里tokenRequest是請求體對象,將會由Fastjson序列化為JSON字符串,它所屬的類無所謂是不是有泛型,因為可以通過member.getClass()獲得(即tokenRequest中所有的成員的類型是確立的且可獲取的);
使用的時候最好用restTemplate.postForEntity()的而不要用restTemplate.postForObject(),后者不能設置Header,而且似乎也不能執行Multipart請求;
二:有泛型的情況
CommonResponse<TokenDataModel> response = restTemplate.postForObject(remoteUrl, tokenRequest, CommonResponse.class);
這個時候就有問題了,因為CommonResponse在字節碼里是泛型擦除的,它所有的泛型成員本質上就是一個Object類型的子類但是.class里沒有記錄到底是什么具體類,因此當獲取的response的JSON字符串中:
{ "code": 8209, "code_description": "APPLICANT_SUCCESS", "data": { "cell_phone_number": "1111111111", "collect_website": "中國聯通","token": "77785fb276ed47cb9a01ec52f9a133c8" }, "message": "成功" }
將data部分轉換為泛型成員時RestTemplate將不知道該怎么轉換,如果將T類型認為是Object,那么顯然Object是沒有cellPhoneNumber之類的屬性的,所以RestTemplate的做法是將data部分的JSON字符串轉換為了LinkedHashMap對象(key-value對);
三:解決方式
通過RestTemplate的exchange方法來解決:
ParameterizedTypeReference<CommonResponse<TokenDataModel>> typeRef = new ParameterizedTypeReference<CommonResponse<TokenDataModel>>() {};
// exchange並不對應於任何一種method,如GET、POST、PUT、DELETE,因此需要手動指定 CommonResponse<TokenDataModel> response = restTemplate.exchange(remoteUrl, HttpMethod.POST, new HttpEntity<>(tokenRequest), typeRef).getBody();
四:單純用Fastjson轉換有泛型的類的方式
CommonResponse<TokenDataModel> response = JSON.parseObject("{json string}", new com.alibaba.fastjson.TypeReference<CommonResponse<TokenDataModel>>(){});
五:原理
在java里,泛型類編譯成.class后確實是泛型擦除,但是泛型類對象里是會(間接)存儲泛型的實際類型的,因此需要new TypeReference<Test<RealType>>(){}產生一個對象;
它內部是:
// 獲取匿名類對象的Generic父類,即Test<RealType>類型 // 注意superClass並不是Class類對象,它應該理解為: // 為泛型類的子匿名類對象產生的一個與之一一對應的Type類對象(這個倒像真泛型) // 這個Type類對象里存儲了此匿名類對象的所有泛型信息 Type superClass = getClass().getGenericSuperclass();
