java 参数化类_Java反射-基于ParameterizedType实现泛型类类型参数化

反射机制是Java的一个非常实用的特性. 基于反射, 我们可以实现下面的接口

T foo(..., Class tClass);

将类型作为参数传入方法中, 方法可以根据具体的类实现不同的逻辑, 返回不同数据类型的结果. 这十分有利于减少代码的冗余度和耦合度, 在复杂多样的业务场景中非常有用.

然而, 当反射遇到泛型, 问题就变的棘手起来. 我们常常会遇到这么一个情景: 类型参数是继承了某个泛型类的子类的参数, 我们需要根据泛型基类和子类参数, 构造出子类类型. 与List, Map 等子类不一样, 这里的子类类型参数是动态指定的.

举个例子, 在开发中, 我们经常需要接入一些外部系统的Restful API. 通常, 除了业务数据部分外, 这些API的请求构建, 响应处理的逻辑都是一样的. 自然而然, 我们会想把接口的请求逻辑封装为一个方法来实现复用. 然而, 在处理响应的过程中, 我们需要对接口的返回结果进行反序列化. 假设外部接口返回的数据结构如下

@Data

public class ResponseDTO {

private String code;

private String message;

private T data;

}

T 为业务数据类型, 不同的接口业务数据结构会不一样. 我们需要根据 ResponseDTO 和 T, 反射出类型 ResponseDTO . 如果实现不了泛型类的参数化, 对于每一个业务接口的数据类型T, 我们都要显式继承 ResponseDTO 得到静态的子类类型, 未免特别冗余和不优雅.

幸好, 至 Java 1.7 开始, java.lang.reflect 提供了Interface ParameterizedType. 通过实现这个接口, 我们可以实现泛型类的类型的参数化, 代码如下:

public class ParameterizedTypeImpl implements ParameterizedType {

private final Class raw;

private final Type[] args;

private final Type owner;

public ParameterizedTypeImpl(Class raw, Type[] args, Type owner) {

this.raw = raw;

this.args = args != null ? args : new Type[0];

this.owner = owner;

}

@Override

public Type[] getActualTypeArguments() {

return args;

}

@Override

public Type getRawType() {

return raw;

}

@Override

public Type getOwnerType() {

return owner;

}

}

利用这个类, 我们就可以实现参数化类型, 封装出某外部系统通用的HTTP调用方法:

GET请求

private T myHttpGet(HttpGet httpGet, Type dataType) {

HttpClient httpClient = HttpClients.createDefault();

try {

HttpResponse response = httpClient.execute(httpGet);

if (response.getStatusLine().getStatusCode()== HttpStatus.SC_OK) {

String result = EntityUtils.toString(response.getEntity());

Type parameterizedTypeClass = // 构造响应类型 ResponseDTO

new ParameterizedTypeImpl(ResponseDTO.class, new Type[]{dataType}, ResponseDTO.class);

ResponseDTO responseBody = gson.fromJson(result, parameterizedTypeClass); //使用GSON反序列化响应

if (responseBody.getCode() != 0) {

throw new MyException(

String.format("[MY.HttpGet]请求失败, url=%s, details=%s",

httpGet.getURI(), gson.toJson(responseBody.getMessage())),

MyErrorCode.ES_REQUEST_FAIL);

}

return responseBody.getContent();

}

throw new MyException("[MY.HttpGet]" + response.getStatusLine().toString(), MyErrorCode.ES_REQUEST_FAIL);

} catch (Exception ex) {

throw new MyException("[MY.HttpGet]" + ex.getMessage(), MyErrorCode.ES_REQUEST_FAIL);

}

}

POST请求

private T myHttpPost(HttpPost httpPost, Type dataType) {

HttpClient httpClient = HttpClients.createDefault();

try {

HttpResponse response = httpClient.execute(httpPost);

if (response.getStatusLine().getStatusCode()== HttpStatus.SC_OK){

String result= EntityUtils.toString(response.getEntity());

Type responseTypeClass = // 构造响应类型 ResponseDTO

new ParameterizedTypeImp(ResponseDTO.class, new Type[]{dataType}, ResponseDTO.class);

ResponseDTO responseBody = gson.fromJson(result, responseTypeClass); // 使用GSON反序列化响应

if(responseBody.getCode()!=0) {

throw new MyException(

String.format("[MY.HttpPost]请求失败, url=%s, details=%s",

httpPost.getURI(), gson.toJson(responseBody.getMessage())),

MyErrorCode.ES_REQUEST_FAIL);

}

return responseBody.getContent();

}

throw new MyException("[MY.HttpPost]" + response.getStatusLine().toString(), MyErrorCode.ES_REQUEST_FAIL);

} catch (Exception ex) {

ex.printStackTrace();

throw new MyException("[MY.HttpPost]" + ex.getMessage(), MyErrorCode.ES_REQUEST_FAIL);

}

}

在调用时, 我们构造好请求对象和业务部分数据结构, 就可以得到对应的返回.

HttpPost httpPost = new HttpPost(host + "/api/dataA");

httpPost.addHeader("Content-Type", "application/json; charset=utf-8");

//...

StringEntity se = new StringEntity(gson.toJson(reqBody), "utf-8");

httpPost.setEntity(se);

try {

DataA resbody = myHttpPost(httpPost, DataA.class);

} catch (Exception ex) {

throw new MyException(

"调用接口失败, " + ex.getMessage(),ErrorCode.ES_REQUEST_FAIL);

}

甚至, 泛型类的子类也可以参数化传入:

List resbodyB = myHttpPost(httpPost, new TypeToken>(){}.getType()); // 这里用到Gson的TypeToken

子类的参数类型也可以参数化, 使用ParameterizedTypeImp构造其类型即可:

Type typeDataCP = new ParameterizedTypeImp(DataC.class, new Type[]{tClass}, DataC.class); // Class

tClass

DataC

resbodyC = myHttpPost(httpPost, typeDataCP);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值