实现方案
采用groovy的扩展方法机制,实现methodMissing、propertyMissing。
实现代码
编写扩展类
扩展方法实现类文件ExtGroovyObject.groovy,
扩展实现类不必是groovy,也可以是java。
扩展方法的实现方式:
- 扩展方法实现时都是
static的 - 扩展方法实现的第一个参数都是调用该方法的对象,即
this - 使用扩展方法时和常规方法没有区别
- 如下文的扩展方法
toJson,给所有对象添加了toJson方法,将对象转成JSON字符串,所有对象(包括List或数组)都可以通过实例直接调用toJson - 如:
new String[]{"a"}.toJson()将返回["a"] - 如:
cn.hutool.core.map.MapUtil.of("a","b").toJson()将返回{"a":"b"}
- 如下文的扩展方法
package local.my.ext
import cn.hutool.core.util.ReflectUtil
import cn.hutool.json.JSONUtil
import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport
import org.codehaus.groovy.runtime.NullObject
/**自定义扩展类,需要配置到{@code org.codehaus.groovy.runtime.ExtensionModule}文件中才起作用*/
class ExtGroovyObject extends DefaultGroovyMethodsSupport{
/**转换成json字符串
* @param self 即调用者this
* */
static String toJson(Object self) {
if (self == null || self == NullObject.getNullObject()) {
return null
}
return JSONUtil.toJsonStr(self)
}
/**调用私有方法找不到则反射调用父类
* @param self 即调用者this
* @param name 未找到的方法名称
* @param args 要调用的方法参数列表*/
static def methodMissing(Object self,String name, def args) {
ReflectUtil.invoke(self,name,args)
}
/**获取私有成员变量找不到则反射调用父类
* @param self 即调用者this
* @param name 未找到的属性名称
* */
static def propertyMissing(Object self, String name) {
ReflectUtil.getFieldValue(self,name)
}
/**设置私有成员变量找不到则反射调用父类
* @param self 即调用者this
* @param name 未找到的属性名称
* @parqm value 要设置的属性值
* */
static def propertyMissing(Object self, String name,def value) {
ReflectUtil.setFieldValue(self,name,value)
}
}
编写配置文件
在项目resources目录下下添加子目录META-INF/groovy,并在groovy目录中添加文件org.codehaus.groovy.runtime.ExtensionModule。
# 自定义模块名称
moduleName=Test module for specifications
# 自定义模块版本
moduleVersion=1.0-test
# 自定义扩展类的全路径
extensionClasses=local.my.ext.ExtGroovyObject
测试
测试对象:
package local.my;
public class TestDo {
private int i=1;
private String say(){
return "nothing";
}
public static class TestDo2 extends TestDo {
private int j=2;
}
}
测试方法:
package local.my
import org.junit.jupiter.api.Test
class TestGroovy {
@Test
static void test() {
def o = new TestDo.TestDo2()
assert o.i == 1
assert o.j == 2
o.tap {
i=3
j=4
assert i== 3
assert j== 4
}
}
assert o.say() == "nothing"
}