今天在写脚本的时候发现一个奇怪的错误。经过猜想验证,发现原来Groovy过于灵活了,算是重复踩了之前的坑。Groovy特性描述如下:
当Groovy脚本调用getFun()和setFun()方法时,会默认给这个类有一个FunTester的属性。反过来,如果这个类有Fun这个属性,那么get和set方法是不用显式写出来的。
本来这是个好事情,一方面其实可以免去多余代码,一方面更容易收拢入口方法(因为直接访问属性、修改属性也是有限调用get和set方法)。
但是就是这个特性让我下面的代码报错了。
```
StringBuilder sb = new StringBuilder()
for (int i = 0; i < 3; i++) {
sb.append("a" + i)
output(sb.toString())
sb.setLength(0)
}
```
其中java.lang.AbstractStringBuilder#setLength方法是用来裁剪StringBuilder对象内容的,如果参数为0,实际的功效就是清空。
官方的描述为:
`setLength(int newLength)` 是 `AbstractStringBuilder` 类中的一个方法,用于设置字符串的长度。具体来说,它有以下作用:
- 如果 `newLength` 小于当前字符串的长度,则字符串将被截断为指定的长度 `newLength`。
- 如果 `newLength` 大于当前字符串的长度,则在字符串末尾填充空字符('\0')直到字符串达到指定的长度 `newLength`。
下面是我代码报错信息:
```
No signature of method: java.lang.StringBuilder.setLength() is applicable for argument types: (Integer) values: [0]
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:70)
at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:46)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:139)
```
错误信息显示并没有这个方法,真是见了鬼了,我在Intellij里面查看源码时明明显示没有问题。当我把问题抛给ChatGPT,得到如下回答。
这个错误信息是Groovy中的一个问题,可能是因为Groovy与Java在`StringBuilder`类的操作上存在某些不同。`setLength()`方法通常用于设置`StringBuilder`的长度,但是错误信息表明`setLength()`方法似乎被错误地调用,传递了一个不正确的参数类型。在Java中,`setLength()`方法接受一个`int`类型的参数,表示要设置的新长度。但是在错误信息中显示传递了`Integer`类型的值 `[0]`,这可能导致方法调用失败。如果问题仍然存在,可能需要进一步检查Groovy代码中的其他部分,以确保在`StringBuilder`操作方面没有其他的语法错误或问题。
这个时候我才意识到这是一个Groovy的报错,并不是Java的。所以,根据我多年踩坑经验早就的敏感度,set方法一定是出问题了。经过我检查,StringBuilder类并没有length属性,这就是导致报错的根本原因。
下面我来验证自己的猜想,通过Groovy元编程给StringBuilder类加上这个length属性。
```
StringBuilder.metaClass.length= 32
StringBuilder sb = new StringBuilder()
for (int i = 0; i < 3; i++) {
sb.append("a" + i)
output(sb.toString())
sb.setLength(0)
}
```
这下不报错了,但问题来了,setLength功能不起作用了,因为优先去设置属性值去了。看来虽然验证了,但是功能破坏了,只好用点笨办法了。
```
StringBuilder.metaClass.length= 32
StringBuilder sb = new StringBuilder()
for (int i = 0; i < 3; i++) {
sb.append("a" + i)
output(sb.toString())
}
```
这个就解决了所有问题。当我去用Java代码中验证时,发现一直没有报错。我换了个项目(Maven/Gradle)结果发现居然无法复现了。哎,又遇到幽灵的问题,可能Groovy在编译这个项目类的时候开小差了。我的JDK版本17,Groovy编译插件版本3.0.1,重新清空本地缓存重启Intellij也依然如此。
通过对比两个项目差异,同时升级Groovy依赖版本和编译插件版本,改缺陷自动解决了。
> - [900原创合集](https://mp.weixin.qq.com/s/lDZ344i0N_red3zy06MRLw)
> - [2021年原创合集](https://mp.weixin.qq.com/s/ziuOuueP6tN2U7dF06axkw)
> - [2022年原创合集](https://mp.weixin.qq.com/s/Ztet8pky58B8RBLWrqdrpg)
> - [接口功能测试专题](https://mp.weixin.qq.com/s/yp4Y0RHmGsozxWzPAL4SXw)
> - [性能测试专题](https://mp.weixin.qq.com/s/0PJGfWT49rkw2uRbcezf4w)
> - [Groovy专题](https://mp.weixin.qq.com/s/wsk4ggKoRiqkQqL7uN9dPg)
> - [Java、Groovy、Go、Python](https://mp.weixin.qq.com/s/LrcAe7M6dUigysM01RpvkQ)
> - [单测&白盒](https://mp.weixin.qq.com/s/IK1aF4ScRE8qRhbEULBzgA)
> - [FunTester社群风采](https://mp.weixin.qq.com/s/bBJUgwOwJv3veRwVkVVfqQ)
> - [测试理论鸡汤](https://mp.weixin.qq.com/s/67jXEMIJZQZ_EMW2tSJsBA)
> - [FunTester视频专题](https://mp.weixin.qq.com/s/Z6wacRieYeJJSEDxj8_S-A)
> - [案例分享:方案、BUG、爬虫](https://mp.weixin.qq.com/s/5nFwT0ACYmIHXfP9HYSZWg)
> - [UI自动化专题](https://mp.weixin.qq.com/s/AnefdNf8izkkpmPxNphhQg)
> - [测试工具专题](https://mp.weixin.qq.com/s/2PkPIaCFGOPCUP2P44a2iw)