一个应用使用 Spring Mvc 实现的 RESTFul Webservice,其Controller 用下面的类包装结果返回给调用方。
public class BaseResponse<T> {
private String msg = "message not set";
private T data;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
我们调用方就直接使用 Spring 的 RestTemplate 调用其服务,调用过程中发现如果有个时间字段被序列化成 Long 型,会导致简单的 Gson 反序列化出问题。网上搜了下解决方案蛮多,就抄了个下面的:
public class GsonUtil {
public static Gson getDateGson() {
JsonDeserializer<Date> dateJsonDeserializer = (json, typeOfT, context) -> json == null ? null : new Date(json.getAsLong());
return new GsonBuilder().registerTypeAdapter(Date.class,dateJsonDeserializer).create();
}
}
然后封装下 RestTemplate:
public class SpringRest<T> {
private Type type;
private RestTemplate rest;
public SpringRest(Type type){
rest = new RestTemplate();
this.type = type;
}
public T doGet(String url){
ResponseEntity<String> entity = rest.getForEntity(url, String.class);
return getResult(entity);
}
public T doPost(String url, Object input){
ResponseEntity<String> entity = rest.postForEntity(url, input, String.class);
return getResult(entity);
}
private T getResult(ResponseEntity<String> entity) {
String str = entity.getBody();
BaseResponse<T> resp = GsonUtil.getDateGson().fromJson(str, type);
return resp.getData();
}
}
这里本来不打算定义 type 属性,而是直接在 getResult 方法的 fromJson 里直接传如 new TypeToken<BaseResponse<T>>() {}.getType(),也即:
BaseResponse<T> resp = GsonUtil.getDateGson().fromJson(str, new TypeToken<BaseResponse<T>() {}.getType());
但真正执行时,不起作用,T 不能运行时替换成实际类型,所以把 type 的实例作为构造函数的参数传入。测试代码:
public class Test {
public static void main(final String[] args) throws Exception {
SpringRest<List<Project>> rest = new SpringRest<>(new TypeToken<BaseResponse<List<Project>>>() {}.getType());
List<Project> projects = rest.doGet("http://localhost:8090/MyApp/project/21/projects");
for (Project p : projects){
System.out.println(p.getName());
}
}
}