如何在Feign接口中返回一个泛型类?
在feign接口中返回泛型类时,由于java的泛型机制,在实例化之前无法得到具体的类型 ,因此,虽然服务提供方返回的是具体实例的数据,但是在客户端decode时,无法转化为具体的类。
例如
@RequestMapping("getGoodByCode")
<T extends BaseEntity> ObjectResponse<T> geByCode(@RequestParam("code") String code,@RequestParam("type") String type);
1
2
此接口 通过商品code和类型获取商品类,此时我们只能接收到只能是ObjectResponse<BaseEntity> 即使服务方返回的是 ObjectResponse<Goods>。
解决办法
服务提供方返回泛型类型的全限定名 如com.****.product.Goods 可放在header中
客户端继承Decoder 接口,重写decode方法。
得到类名后和response数据.
通过反射实例化Goods,得到Goods 的Class类
通过反序列化,得到Goods 类实例,
然后set Response.setModel(goods )
Decoder
public class CustomDecoder implements Decoder {
//泛型的classType ,,decode 方法进行手动解析.
public final static String genericsHeader = "generics-header";
private Decoder decoder;
public CustomDecoder(Decoder decoder) {
this.decoder = decoder;
}
@Override
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
Object returnObject = null;
if (isParameterizeHttpEntity(type)) {
type = ((ParameterizedType) type).getActualTypeArguments()[0];
Object decodedObject = decoder.decode(response,type);
returnObject = createResponse(decodedObject, response);
}
else if (isHttpEntity(type)) {
returnObject = createResponse(null, response);
}
else {
returnObject = decoder.decode(response, type);
}
//以上是原默认实现,复制过来,为了拿到returnObject
if(returnObject !=null) {
Map<String, Collection<String>> map = response.headers();
if (returnObject instanceof ObjectResponse) {
Collection<String> list = map.get(genericsHeader);
if(list!=null){
Object object = ReflectUtil.newInstance(((LinkedList)list).get(0).toString());
String body = IoUtil.read(response.body().asInputStream(),"UTF-8");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
JsonNode jsonNode = objectMapper.readTree(body);
if(!jsonNode.get("success").booleanValue()){
return returnObject;
}
//拿出result ,实例化对象(genericsHeader 指定的类型),然后重新set
String result = jsonNode.get("model").toString();
((ObjectResponse) returnObject).setModel(objectMapper.readValue(result,object.getClass()));
}
}
}
// log.info("计算耗时:{}",System.currentTimeMillis()-start);
return returnObject;
}
private boolean isParameterizeHttpEntity(Type type) {
if (type instanceof ParameterizedType) {
return isHttpEntity(((ParameterizedType) type).getRawType());
}
return false;
}
private boolean isHttpEntity(Type type) {
if (type instanceof Class) {
Class c = (Class) type;
return HttpEntity.class.isAssignableFrom(c);
}
return false;
}
@SuppressWarnings("unchecked")
private <T> ResponseEntity<T> createResponse(Object instance, Response response) {
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
for (String key : response.headers().keySet()) {
headers.put(key, new LinkedList<>(response.headers().get(key)));
}
return new ResponseEntity<>((T) instance, headers, HttpStatus.valueOf(response
.status()));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
ObjectResponse
public class ObjectResponse<T> {
private boolean success;
private String msg;
private T model;
public boolean isSuccess() {
return success;
}
public ObjectResponse<T> setSuccess(boolean success) {
this.success = success;
return this;
}
public String getMsg() {
return msg;
}
public ObjectResponse<T> setMsg(String msg) {
this.msg = msg;
return this;
}
public T getModel() {
return model;
}
public ObjectResponse<T> setModel(T model) {
this.model = model;
return this;
}
}
推荐阅读