专栏首页软件测试那些事切面获取泛型方法T的真实类型

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

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

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

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

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的录制回放的基本套路就是通过获取到被录制的方法的返回值类型来进行回放。

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

@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>”, 这也就意味着以下反序列化方法的执行失败。

GsonUtil.fromJson(record.getReturning(),returnType);

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

问题解决

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

这是Class类的定义,

public final class Class<T> implements
 Serializable,
GenericDeclaration,
 Type,
 AnnotatedElement {
}

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

有如下的方式,

proceed = pjp.proceed();
String typeName=proceed.getClass().getTypeName();
if (returnType.getTypeName().equals("T") || 
returnType.getTypeName().equals("java.util.List<T>")) {

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

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

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 删除。
登录 后参与评论
0 条评论

相关文章

  • 泛型类、泛型方法、类型通配符的使用

           你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

    泰斗贤若如
  • 如何获取泛型类的参数化类型?

    我在基于XXL-JOB进行二次开发的XXL-JOB-ONION分布式定时任务调度系统项目中,添加了一个ONION_BEAN的运行模式,约定定时任务必须通过实现O...

    Java艺术
  • ArrayList的toArray()方法为啥不利用泛型返回List的泛型类型的数组探究

    有些同学提出“ArrayList的public T[] toArray(T[] a) 带参数的方法支持泛型可以返回参数类型的数组,public Object[...

    明明如月学长
  • 生成代码,从 T 到 T1, T2, Tn —— 自动生成多个类型的泛型

    发布于 2018-01-31 05:38 更新于 2018-05...

    walterlv
  • 根据java编译器规则在Class中搜索匹配指定参数类型表的泛型方法(GenericMethod)

    因为项目的需要,设计了一个满足特定需要的代码自动生成工具。在开发过程中需要根据方法名和方法参数类型数组在指定的类中根据java编译器的规则找到与之最匹配的泛型方...

    用户1148648
  • 基础篇:深入解析JAVA注解机制

    在代码里定义的注解,会被jvm利用反射技术生成一个代理类,然后和被注释的代码(类,方法,属性等)关联起来

    潜行前行
  • 切面中如何实现泛型返回值的反序列化

    在Http服务的远程调用中,HTTP请求的响应是这样定义的 @Data class ResponseResult { String errorCode; Str...

    Antony
  • Java | 泛型实现机制

    泛型的本质是参数化类型,就是将原来的具体的类型参数化。在不确定需要类型的情况下,通过泛型来指定具体的限制

    345
  • 思想:java中,父类的方法中传入的形参的数据类型是泛型,子类的方法的形参想只要一种确定的数据类型,子类该如何做呢?

    黑泽君
  • 代理、反射、注解、hook

    通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,扩展目标对象的功能。 代理对象拦截真实对象的方法调用,在真实对象调用前/后实现自己的逻辑...

    六月的雨
  • 深入分析Java反射(三)-泛型

    Java反射的API在JavaSE1.7的时候已经基本完善,但是本文编写的时候使用的是Oracle JDK11,因为JDK11对于sun包下的源码也上传了,可以...

    Throwable
  • fastjson为何使用TypeReference?

    fastJson 的泛型反序列化场景经常使用到 TypeReference,如下示例:

    JavaEdge
  • .NET面向上下文、AOP架构模式(实现)

    在本人的.NET面向上下文、AOP架构模式(概述)一文中,我们大概了解了上下文如何辅助对象在运行时的管理。在很多时候我们急需在运行时能把对象控制在一定的逻辑范围...

    王清培
  • ASP.NET Core中的依赖注入(3): 服务的注册与提供

    在采用了依赖注入的应用中,我们总是直接利用DI容器直接获取所需的服务实例,换句话说,DI容器起到了一个服务提供者的角色,它能够根据我们提供的服务描述信息提供一个...

    蒋金楠
  • Spring 自定义注解你了解过吗?

    https://juejin.im/post/5cf376e16fb9a07eee5eb6eb

    南风
  • Spring 自定义注解从入门到精通

    在业务开发过程中我们会遇到形形色色的注解,但是框架自有的注解并不是总能满足复杂的业务需求,我们可以自定义注解来满足我们的需求。根据注解使用的位置,文章将分成字段...

    芋道源码
  • 深入理解Kotlin的泛型系统

    Kotlin 的泛型与 Java 一样,都是一种语法糖,只在源代码里出现,编译时会进行简单的字符串替换。

    砸漏
  • 一文带你读懂 Java 泛型

    type)的应用,可以声明在类、接口或者方法上。没有泛型时可以用Object结合强制类型转化实现相似需求,但是运行时风险就明显了,泛型就是用于解决这个问题的。

    大发明家
  • C Sharp(十二)

    没有泛型的时候,我们封装的行为都是作用在特定类型上的,但是,很多时候如果我们把行为提取或重构出来,使其可以应用到很多类型上去的话,那么就会更有意义。这也是泛型出...

    1ess

扫码关注腾讯云开发者

领取腾讯云代金券