背景
今天测试环境出现了一个错误,错误原因很简单,Mybatis Mapper文件在传递参数的时候没有使用 Param
注解。 在Mybatis中,如果要传递多个参数必须使用 @Param
注解,否则会出现获取参数失败的情况。
作为一个有点懒惰的开发,我是希望把 @Param
注解去掉的,于是我去Github Mybatis的issue搜索了一圈,发现也有同学有这样的问题和需求。
于是我就开始想,为什么SpringMVC可以获取到参数,而Mybatis就不行呢,于是我打算用ASM获取一下参数(SpringMVC是使用ASM来做的),我立马就把以前的代码Copy过来
- 调试一下带body的方法,跑通了。
- 又测试了一个Interface,失败了。
调试
于是在休息的时候,我开始对ASM的过程进行debug,使用过ASM的同学都知道,他是对class文件进行依次visit处理的过程,结果却发现interface的method压根就进不去哪些方法,直接来到了visitEnd. 自然就获取不到参数了。
我马上开始Google, 中文网上都是对ASM的介绍,于是我又去stackoverflow查看问题,果然被我查到了。但是这里的结论只是描述了interface的method是不行的,但是为什么不行,则没有进行描述。这个有点不符合stackoverflow的提问哲学。
emmmmm,我最后把我的发现结果回复了这个问题,还迎来了2个反对,丢失了4分,得不偿失,得不偿失呀 🤣🤣🤣🤣🤣🤣🤣
果然我遇到的问题,都有人遇到过了。
我又想到ASM issue去看看什么情况,但是也没有找到问题,在找的过程中,猛滴想到ASM本身就是解析class文件的, 于是使用javap查看情况。
public interface FF {
default void hh(String name) {
}
String hello(String hello);
}
Javap执行结果,如下所示,interface的hello方法,是没有body体的,同时也没有LocalVariableTable,而我如果要获取参数,就必须以来这里的LocalVariableTable。所以我无法获取到参数,只能通过注解来实现。
➜ ~ javap -v /Users/chenshun/tool/winter/target/test-classes/io/github/chenshun00/web/asm/FF.class
Classfile /Users/chenshun/tool/winter/target/test-classes/io/github/chenshun00/web/asm/FF.class
Last modified 2022-7-15; size 384 bytes
MD5 checksum de24290be11cb7706f83d3a355261367
Compiled from "FF.java"
public interface io.github.chenshun00.web.asm.FF
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
Constant pool:
#1 = Class #16 // io/github/chenshun00/web/asm/FF
#2 = Class #17 // java/lang/Object
#3 = Utf8 hh
#4 = Utf8 (Ljava/lang/String;)V
#5 = Utf8 Code
#6 = Utf8 LineNumberTable
#7 = Utf8 LocalVariableTable
#8 = Utf8 this
#9 = Utf8 Lio/github/chenshun00/web/asm/FF;
#10 = Utf8 name
#11 = Utf8 Ljava/lang/String;
#12 = Utf8 hello
#13 = Utf8 (Ljava/lang/String;)Ljava/lang/String;
#14 = Utf8 SourceFile
#15 = Utf8 FF.java
#16 = Utf8 io/github/chenshun00/web/asm/FF
#17 = Utf8 java/lang/Object
{
public void hh(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=0, locals=2, args_size=2
0: return
LineNumberTable:
line 17: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 this Lio/github/chenshun00/web/asm/FF;
0 1 1 name Ljava/lang/String;
public abstract java.lang.String hello(java.lang.String);
descriptor: (Ljava/lang/String;)Ljava/lang/String;
flags: ACC_PUBLIC, ACC_ABSTRACT
}
SourceFile: "FF.java"
同时,我也发现了,这种问题不是个例,例如feign的interface定义,也必须是要使用注解的,可以是springmvc的,也可以使用feign本身的。其原因大概如此。
总结
在移除 Param
注解路上,发现了为什么SpringMVC为什么可以不需要注解,而Mybatis又必须依赖注解,解决问题的路上稍微有点曲折,但是最终还是解决了。 丢失了4分我有些不解
so bad,在我写这个的时候又收获了一个反对票,-6分。