前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >切面获取泛型方法T的真实类型

切面获取泛型方法T的真实类型

作者头像
Antony
发布2021-08-06 10:59:27
2.1K0
发布2021-08-06 10:59:27
举报

随着ServiceMock项目的推广实施,遇到的坑也越来越稀奇古怪了。

这次是介绍一个使用了Mybatis Pro的项目中遇到的问题。Mybatis是在Spring项目中非常常见的持久层框架。在享受其带来的便利的同时,也给SeriveMock带来了新的挑战。

有如下的一个典型的数据库Mapper的类。

代码语言:javascript
复制
import java.util.List;
import tk.mybatis.mapper.entity.Example;
public interface BaseService<T> {
   public List<T> selectAll();
   public List<T> selectByExample(Example example);
   public T selectByPrimarikey(Object key);
   public int updateByPrimarikey(T t);
   public int updateByExample(T t,Example example);
   public int insert(T t);
   public int insertList(List<T> t);
   public int deleteByPrimarikey(Object key);
   public int deleteByExample(Example example);}

*源码来自网络。

制造问题的是起头的这三个泛型的方法。如 selectByPrimaryKey这个方法,由于这是一个泛型方法,其返回值为T 。

而ServiceMock的录制回放的基本套路就是通过获取到被录制的方法的返回值类型来进行回放。

简单来说,是这样的一个过程,

代码语言:javascript
复制
@Around("recordLog()")
public Object around(ProceedingJoinPoint pjp) 
throws Throwable {    
 MethodSignature signature = (MethodSignature) pjp.getSignature();
 Type returnType =signature.getMethod().
                 getAnnotatedReturnType().getType();
 
//***
return GsonUtil.fromJson(record.getReturning(),returnType);
 
}

通过切面获取到了执行中的方法,然后根据方法的returnType来对录制的数据进行反序列化并作为本次执行的结果返回,从而就实现了对服务依赖的回放。

而如果是泛型的方法,那么returnType的结果就是“T”或者是”List<T>”, 这也就意味着以下反序列化方法的执行失败。

代码语言:javascript
复制
GsonUtil.fromJson(record.getReturning(),returnType);

反序列化时,gson并不知道T具体是什么类型,导致反序列化的失败,或者List<T>会被以List<Object>的方式进行反序列化,造成了在回放时的数据类型与调用者的预期不匹配。

问题解决

在被这个问题卡壳之后,还是要重新温习一下Java的基础。

这是Class类的定义,

代码语言:javascript
复制
public final class Class<T> implements
 Serializable,
GenericDeclaration,
 Type,
 AnnotatedElement {
}

可以看到, Class类实现了Type接口。这样,只要获取到了切点中正在执行方法的返回值(原始类型或者是某个类的实例),然后根据返回值来获取到Class,并最终获取到Type。这样就可以继续愉快地进行反序列化了。

有如下的方式,

代码语言:javascript
复制
proceed = pjp.proceed();
String typeName=proceed.getClass().getTypeName();
if (returnType.getTypeName().equals("T") || 
returnType.getTypeName().equals("java.util.List<T>")) {

对于T 或者是List<T>的泛型方法,就在执行时获取一下执行类型并记录。

而在回放时,可以通过获取记录的类型来进行反射,获取对应的类,并最终实现反序列化。

代码语言:javascript
复制
if(returnType.getTypeName().equals("T")) { 
   Class clazz=Class.forName(record.getReturnType()); 
     return GsonUtil.fromJson(data,clazz);
      }

于是,就可以继续愉快地进行录制回放了。

当然,坑还是要继续填的。例如,

  • selectByPrimarikey 可能返回Null,也就是查无记录。
  • List在反序列化时,只能根据List<Object>进行反序列化,不能同时指定List中记录的类型。
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 软件测试那些事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档