groovy 中的 get 与 getProperty

2024-01-14

令我惊讶的是!

根据groovy的文档,groovy可以使用“getProperty”方法来获取对象的属性。因此,当我想更改获取特殊对象属性的行为时,我使用类别类来重写“getProperty”方法。然而,它不起作用。 最后,我发现groovy框架使用类别类中的“get”方法来获取属性,即使对象不是地图。 我的问题是,这是一个错误还是像这样工作。

这是类别类。

class DynaBeanExtension {

    public static void setProperty(DynaBean bean, String propertyName, def newValue) {
        try {
            PropertyUtilsBean pu = null;
            if (bean instanceof CustomWrapDynaBean) {
                pu = bean.propertyUtilsBean;
            }
            if (pu != null) {
                pu.setProperty(bean, propertyName, newValue);
            } else {
                PropertyUtils.setProperty(bean, propertyName, newValue);
            }
        } catch (IllegalArgumentException ex) {
            bean.propertyMissing(propertyName, newValue);
        }
    }

    public static def getProperty(DynaBean bean, String propertyName) {
        try {
            PropertyUtilsBean pu = null;
            if (bean instanceof CustomWrapDynaBean) {
                pu = bean.propertyUtilsBean;
            }
            if (pu != null) {
                return pu.getProperty(bean, propertyName);
            } else {
                return PropertyUtils.getProperty(bean, propertyName);
            }
        } catch (IllegalArgumentException ex) {
            return bean.propertyMissing(propertyName);
        }
    }

    public static def get(DynaBean bean, String propertyName) {
        try {
            PropertyUtilsBean pu = null;
            if (bean instanceof CustomWrapDynaBean) {
                pu = bean.propertyUtilsBean;
            }
            if (pu != null) {
                return pu.getProperty(bean, propertyName);
            } else {
                return PropertyUtils.getProperty(bean, propertyName);
            }
        } catch (IllegalArgumentException ex) {
            return bean.propertyMissing(propertyName);
        }
    }

这是测试代码:

public static class TestSubClass {

    private final int e = 3, f = 4;
    private final Map<String, Object> m = new HashMap<>();

    public int getE() {
        return e;
    }

    public int getF() {
        return f;
    }

    public Map<String, Object> getM() {
        return m;
    }

    @Override
    public String toString() {
        return "TestSubClass{" + "e=" + e + ", f=" + f + ", m=" + m + '}';
    }

}

public static class TestClass {

    private final int a = 1;
    private final TestSubClass b = new TestSubClass();

    public int getA() {
        return a;
    }

    public TestSubClass getB() {
        return b;
    }

    @Override
    public String toString() {
        return "TestClass{" + "a=" + a + ", b=" + b + '}';
    }

}

Map<String, String> pMap = new HashMap<>();
pMap.put("b.e", "c");
PropertyUtilsBean pu = new PropertyUtilsBean();
pu.setResolver(new ExResolver(pMap));
TestClass testObj = new TestClass();
DynaBean bean = new CustomWrapDynaBean(testObj, pu);

int c = use(DynaBeanExtension) {
    bean.c;
}

这是ExResolver的代码:

public class ExResolver implements Resolver {

    private static final char NESTED = '.';
    private static final char MAPPED_START = '(';
    private static final char MAPPED_END = ')';
    private static final char INDEXED_START = '[';
    private static final char INDEXED_END = ']';

    private final Resolver resolver;
    private final Map<String, String> pMap;

    public ExResolver(Map<String, String> pMap) {
        this(new DefaultResolver(), pMap);
    }

    public ExResolver(Resolver resolver, Map<String, String> pMap) {
        this.resolver = resolver;
        this.pMap = new HashMap<>(pMap);
    }

    private String resolveExpr(String expression) {
        for (Map.Entry<String, String> entry : pMap.entrySet()) {
            if (expression.startsWith(entry.getValue())) {
                String to = entry.getValue();
                if (expression.length() == entry.getValue().length()) {
                    return entry.getKey();
                } else {
                    int toTest = expression.codePointAt(to.length());
                    if (toTest == NESTED || toTest == MAPPED_START || toTest == INDEXED_START) {
                        return entry.getKey() + expression.substring(to.length(), expression.length());
                    } else {
                        return expression;
                    }
                }
            }
        }
        return expression;
    }

    @Override
    public int getIndex(String expression) {
        expression = resolveExpr(expression);
        return resolver.getIndex(expression);
    }

    @Override
    public String getKey(String expression) {
        expression = resolveExpr(expression);
        return resolver.getKey(expression);
    }

    @Override
    public String getProperty(String expression) {
        expression = resolveExpr(expression);
        return resolver.getProperty(expression);
    }

    @Override
    public boolean hasNested(String expression) {
        expression = resolveExpr(expression);
        return resolver.hasNested(expression);
    }

    @Override
    public boolean isIndexed(String expression) {
        expression = resolveExpr(expression);
        return resolver.isIndexed(expression);
    }

    @Override
    public boolean isMapped(String expression) {
        expression = resolveExpr(expression);
        return resolver.isMapped(expression);
    }

    @Override
    public String next(String expression) {
        expression = resolveExpr(expression);
        return resolver.next(expression);
    }

    @Override
    public String remove(String expression) {
        expression = resolveExpr(expression);
        return resolver.remove(expression);
    }

}

调用“get”,而不是“getProperty”

更何况,在真实的情况下DynaBeanExtension是用groovy编译的。 bean的构建是用java编译的。然后通过使用binding,我将其放入测试代码中,该代码是由java代码执行的运行时脚本。


这发生在编译本身中。让我们看一个更简单的例子。

class Main {
    static void main(def args) {
        Foo foo = new Foo()
        foo.str = ""
        foo.str
    }
}

对于 Groovy 类

class Foo {
    String str
}

如果你反编译Main类,你会看到它是

public class Main implements GroovyObject {
    public Main() {
        Main this;
        CallSite[] arrayOfCallSite = $getCallSiteArray();
        MetaClass localMetaClass = $getStaticMetaClass();
        this.metaClass = localMetaClass;
    }

    public static void main(String... args) {
        CallSite[] arrayOfCallSite = $getCallSiteArray();
        Foo foo = (Foo)ScriptBytecodeAdapter.castToType(arrayOfCallSite[0].callConstructor(Foo.class), Foo.class);
        String str = "";
        ScriptBytecodeAdapter.setGroovyObjectProperty(str, Main.class, foo, (String)"str");

        arrayOfCallSite[1].callGroovyObjectGetProperty(foo);
    }
}

A .[property] =调用被编译为ScriptBytecodeAdapter.setGroovyObjectProperty,进而调用链MetaClassImpl.setProperty > MetaMethod.doMethodInvoke > CachedMethod.invoke > java.lang.reflect.Method.invoke > [setter]

And a .[property]调用被编译为arrayOfCallSite[1].callGroovyObjectGetProperty,进而调用链AbstractCallSite.callGroovyObjectGetProperty > GetEffectivePogoPropertySite.getProperty > MethodMetaProperty$GetBeanMethodMetaProperty.getProperty > MetaMethod.doMethodInvoke > CachedMethod.invoke > java.lang.reflect.Method.invoke > [getter]

对于 Java 类

如果您使用被调用类的 Java 版本,如下所示

public class Foo {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
}

相同Main反编译为

public class Main implements GroovyObject {
    public Main() {
        Main this;
        CallSite[] arrayOfCallSite = $getCallSiteArray();
        MetaClass localMetaClass = $getStaticMetaClass();
        this.metaClass = localMetaClass;
    }

    public static void main(String... args) {
        CallSite[] arrayOfCallSite = $getCallSiteArray();
        Foo foo = (Foo)ScriptBytecodeAdapter.castToType(arrayOfCallSite[0].callConstructor(Foo.class), Foo.class);
        String str = "";
        ScriptBytecodeAdapter.setProperty(str, null, foo, (String)"str");

        arrayOfCallSite[1].callGetProperty(foo);
    }
}

A .[property] =调用被编译为ScriptBytecodeAdapter.setProperty,进而调用链[Class].setProperty > InvokerHelper.setProperty -> MetaClassImpl.setProperty > MetaMethod.doMethodInvoke > CachedMethod.invoke > java.lang.reflect.Method.invoke > [setter]

And a .[property]调用被编译为arrayOfCallSite[1].callGroovyObjectGetProperty,进而调用链AbstractCallSite.callGetProperty > GetEffectivePojoPropertySite.getProperty > MethodMetaProperty$GetBeanMethodMetaProperty.getProperty > MetaMethod.doMethodInvoke > CachedMethod.invoke > java.lang.reflect.Method.invoke > [getter]

更正您的代码

正如您从这些调度链中看到的,您已经正确地覆盖了 getter(因为它发生在类本身中),但是如果您想覆盖getProperty or setProperty,你必须在metaClass,而不是类本身。您所看到的行为是预期的。此代码演示了如何重写每个

class Foo {
    String bar
}

// override using setter in category
@Category(Foo)
class FooCategory {
    public String getBar() {
        println "in getter"
    }
    public void setBar(String bar) {
        println "in setter"
    }
}
use (FooCategory) {
    Foo foo = new Foo()
    foo.bar = ""
    foo.bar
}

// override using metaClass
Foo.metaClass.getProperty { String pname ->
    println "in getProperty"
}
Foo.metaClass.setProperty { String pname, Object pValue ->
    println "in setProperty"
}
Foo foo = new Foo()
foo.bar = ""
foo.bar

outputs

in setter
in getter
in setProperty
in getProperty

并且因为getProperty/setPropertycall 使调度(最终)到 getter/setter,您可以完全阻止 getter/setter 被调用,如下所示

class Foo {
    String bar
}

Foo.metaClass.getProperty { String pname ->
    println "in getProperty"
}
Foo.metaClass.setProperty { String pname, Object pValue ->
    println "in setProperty"
}

@Category(Foo)
class FooCategory {
    String getBar() {
        println "in getter"
    }
    void setBar(String bar) {
        println "in setter"
    }
}

use (FooCategory) {
    Foo foo = new Foo()
    foo.bar = "hi foo1"
    foo.bar
}

outputs

in setProperty
in getProperty
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

groovy 中的 get 与 getProperty 的相关文章

随机推荐

  • 覆盖不可修改域 Java 类中的 JAXB 绑定

    我花了一整天的时间试图解决这个问题 包括在这个网站上进行广泛的搜索 但我找不到问题的答案 我正在努力实现这一目标 在 XML 和一些我无法控制的现有 Java 对象之间进行转换 结果 源 XML 中的元素名称与 Java 类的属性名称不同
  • 实施面向 3.5 和 4.0 的 .Net 项目

    我们有一个项目 日志记录库 由标准 asp net 应用程序 4 0 框架 和 sharepoint 解决方案 3 5 框架 使用 有没有办法定义两个目标 以便在构建项目时构建两个版本 另外 有人实现了类似的东西并通过 nuget 分发它吗
  • Flutter 在 iOS 设备上出现“连接到服务协议时出错:HttpException...”错误

    对于网络连接我使用dio并用于检查连接状态Connectivity 在这里我检查网络状态 override Widget build BuildContext context bloc checkConnectivity Connectiv
  • jQuery 片段用动画交换两组元素

    是否有一些 jQuery 代码可以用动画交换 2 组元素 我只发现使用 jQuery 将列表项移动到无序列表的顶部 https stackoverflow com questions 1625960 move list item to to
  • 固定表格标题仅水平和垂直滚动 CSS

    首先 是否可以仅使用 CSS 来实现这一点 我已经构建了一个可以水平和垂直滚动的表格 但是 我希望将标题封装在其容器内 而不是出现在包装器之外 这样 当您水平滚动时 相应的标题与其指定列的内容一致 使用不同的变体position absol
  • JBoss AS7自动加载JPA

    我有一个使用 JPA Hibernate 和 Google Guice 的应用程序 Guice 是在一个ServletContextListener它设置了EntityManagerFactory itself 该应用程序在 Tomcat
  • python:numpy 数组的矩阵列表?

    我有一个包含 numpy 矩阵的列表 无论如何 我可以将整个事情变成一个漂亮的干净的 numpy 数组吗 From matrix 1 matrix 1 99387871 matrix 2 53564618 matrix 4 39125807
  • 出现错误 mysqli::real_connect(): (HY000/2002): 当我尝试访问实时服务器上的项目时没有这样的文件或目录[重复]

    这个问题在这里已经有答案了 我已将我的网站上传到服务器 然后尝试访问 但代码点火器向我返回错误 我找不到任何答案 为什么会发生这种情况 我的配置数据库设置如下 db default array dsn gt hostname gt loca
  • JavaScript 中按名称读取 cookie 的最短函数是什么?

    在 JavaScript 中读取 cookie 的最短 准确且跨浏览器兼容的方法是什么 很多时候 在构建独立脚本 我不能有任何外部依赖项 时 我发现自己添加了一个读取 cookie 的函数 并且通常会依赖于QuirksMode orgrea
  • PostgreSQL ANSI、Python SQL、utf-8' 编解码器无法解码字节 0xa0

    我正在尝试在 python 中运行 sql 查询 在 python 2 中 这曾经有效 但现在我使用 python 3 这不再有效 我收到错误UnicodeDecodeError utf 8 codec can t decode byte
  • wx (Python) 小部件的 GUI 更新缓慢?

    考虑这个例子 在 python2 7 Ubuntu 11 04 上尝试过 import wx import wx lib agw knobctrl as KC started from http wxpython org Phoenix d
  • 如何使用 rxjs 定期检查实时连接?

    我使用 rxjs 来处理 websocket 连接 var socket Rx Observable webSocket wss echo websocket org socket resultSelector e gt e data 我想
  • 使用起订量模拟 HttpMessageHandler - 如何获取请求的内容?

    在决定我要发回测试的响应类型之前 有没有办法获取 http 请求的内容 多个测试将使用此类 每个测试将有多个 http 请求 此代码无法编译 因为 lambda 不是async并且有一个await在里面 我是异步等待的新手 所以我不知道如何
  • 使用 docker 在 AWS ray 集群上启动简单的 python 脚本

    我发现遵循 Ray 指南在 ray 集群上运行 docker 映像以执行 python 脚本非常困难 我发现缺乏简单的工作示例 所以我有最简单的docker文件 FROM rayproject ray WORKDIR usr src app
  • Java:高效的ArrayList过滤?

    我需要过滤 ArrayList 并删除找到的元素 作为 Java 的新手 我想知道实现此目的最有效的方法是什么 很重要 因为它在移动设备上运行 目前我这样做 We display only top level dealers parentI
  • 带两个参数的 MVC6 属性路由

    我已经对此进行了查看 并且没有任何与 MVC6 taghelper 锚标记相关的内容与满足多个参数的替代 HttpGet 方法相关 当然 您可以向 MVC6 锚标记帮助器添加多个参数 但是如何使用属性路由处理带有两个参数的第二个选项 我有两
  • 崩溃并终止原因 0xdead10cc

    请问这起事故的原因是什么 Incident Identifier A176CFB8 6BB7 4515 A4A2 82D2B962E097 CrashReporter Key f02957b828fe4090389c1282ca8e3839
  • Windows Phone 7 上带有盐的 SHA1

    我现在花了一些时间研究如何使用盐将密码编码为 SHA1 这是我在网络应用程序部分使用的代码 但它不适用于电话环境 public class Password private string password private int salt
  • Python unicode:如何测试 unicode 字符串

    我有一个这样的脚本 Python26 coding utf 8 import sys import xlrd import xlwt argset set sys argv 1 import wb xlrd open workbook ex
  • groovy 中的 get 与 getProperty

    令我惊讶的是 根据groovy的文档 groovy可以使用 getProperty 方法来获取对象的属性 因此 当我想更改获取特殊对象属性的行为时 我使用类别类来重写 getProperty 方法 然而 它不起作用 最后 我发现groovy