Groovy直接调用父类私有方法,获取父类私有属性

150 阅读2分钟

实现方案

采用groovy的扩展方法机制,实现methodMissingpropertyMissing

参考groovy扩展类官方文档

实现代码

编写扩展类

扩展方法实现类文件ExtGroovyObject.groovy, 扩展实现类不必是groovy,也可以是java。

扩展方法的实现方式:

  1. 扩展方法实现时都是static
  2. 扩展方法实现的第一个参数都是调用该方法的对象,即this
  3. 使用扩展方法时和常规方法没有区别
    • 如下文的扩展方法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"
}