【问题标题】:how to retrieve nested properties in groovy如何在groovy中检索嵌套属性
【发布时间】:2011-07-26 05:05:22
【问题描述】:

我想知道在 Groovy 中检索嵌套属性的最佳方法是什么,采用给定的对象和任意“属性”字符串。我想要这样的东西:

someGroovyObject.getProperty("property1.property2")

我很难找到其他人想要这样做的例子,所以也许我不理解一些基本的 Groovy 概念。似乎必须有一些优雅的方式来做到这一点。

作为参考,Wicket 中有一个功能正是我正在寻找的,称为 PropertyResolver: http://wicket.apache.org/apidocs/1.4/org/apache/wicket/util/lang/PropertyResolver.html

任何提示将不胜感激!

【问题讨论】:

    标签: groovy properties nested resolver getproperty


    【解决方案1】:

    我不知道 Groovy 是否有内置的方法来执行此操作,但这里有 2 个解决方案。在Groovy Console中运行这段代码进行测试。

    def getProperty(object, String property) {
    
      property.tokenize('.').inject object, {obj, prop ->       
        obj[prop]
      }  
    }
    
    // Define some classes to use in the test
    class Name {
      String first
      String second
    }
    
    class Person {
      Name name
    }
    
    // Create an object to use in the test
    Person person = new Person(name: new Name(first: 'Joe', second: 'Bloggs'))
    
    // Run the test
    assert 'Joe' == getProperty(person, 'name.first')
    
    /////////////////////////////////////////
    // Alternative Implementation
    /////////////////////////////////////////
    def evalProperty(object, String property) {
      Eval.x(object, 'x.' + property)
    }
    
    // Test the alternative implementation
    assert 'Bloggs' == evalProperty(person, 'name.second')
    

    【讨论】:

    • 这或多或少是我现在正在做的,但你的方式更干净!
    • 对不起,唐,早就应该接受你的回答了(当我不知道我在这个网站上做什么的时候)。谢谢...
    • 注意:我对这些进行了排序测试,Eval 比我系统上的标记化版本慢得多。
    • 我建议在 getProperty 实现中使用 null 检查。否则,它会在遍历您的对象图时引发空值异常。 (提交编辑)
    【解决方案2】:

    Groovy Beans 让您可以直接访问字段。您不必定义 getter/setter 方法。它们是为您生成的。每当您访问 bean 属性时,都会在内部调用 getter/setter 方法。您可以使用 .@ 运算符绕过此行为。请参阅以下示例:

    class Person {
        String name
        Address address
        List<Account> accounts = []
    }
    
    class Address {
        String street
        Integer zip
    }
    
    class Account {
        String bankName
        Long balance
    }
    
    def person = new Person(name: 'Richardson Heights', address: new Address(street: 'Baker Street', zip: 22222)) 
    person.accounts << new Account(bankName: 'BOA', balance: 450)
    person.accounts << new Account(bankName: 'CitiBank', balance: 300)
    

    如果您不处理集合,您只需调用您要访问的字段即可。

    assert 'Richardson Heights' == person.name
    assert 'Baker Street' == person.address.street
    assert 22222 == person.address.zip
    

    如果要访问集合中的字段,则必须选择元素:

    assert 'BOA' == person.accounts[0].bankName
    assert 300 == person.accounts[1].balance​​​​​​​​​
    

    【讨论】:

    • 这是个好建议,但我希望能够接受一个字符串。有没有办法强制 person."address.street" 返回 person.address.street 的值?
    • 您可以使用Groovy's dynamic method invocation。但是,它需要你声明方法名:person."getAddress"()​."getStreet"()​​​​​​​​​​​​​
    • 感谢您的信息和链接...我会阅读它,看看它是否可以在这里提供帮助。
    • 这是另一种可能更适合您需求的方法。你可以使用Eval类:Eval.x(person, "x.address.street")​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​,可以将Eval类使用。
    • 参考stackoverflow.com/a/15632027/2015517 您可以使用 ${} 语法动态访问 bean 的属性。例如:person.${propertyName}
    【解决方案3】:

    您也可以使用propertyMissing。这就是你可以称之为 Groovy 的内置方法。

    在你的课堂上声明:

    def propertyMissing(String name) {
        if (name.contains(".")) {
            def (String propertyname, String subproperty) = name.tokenize(".")
            if (this.hasProperty(propertyname) && this."$propertyname".hasProperty(subproperty)) {
                return this."$propertyname"."$subproperty"
            }
        }
    }
    

    然后根据需要参考您的属性:

    def properties = "property1.property2"
    assert someGroovyObject."$properties" == someValue
    

    这是自动递归的,您不必显式调用方法。这只是一个 getter,但您也可以定义带有参数的第二个版本来制作 setter。

    缺点是,据我所知,您只能定义一个版本的propertyMissing,因此您必须决定是否要使用动态路径导航。

    【讨论】:

      【解决方案4】:

      https://stackoverflow.com/a/15632027/2015517

      它使用可用作 GString 一部分的 ${} 语法

      【讨论】:

        猜你喜欢
        • 2023-03-22
        • 2012-06-13
        • 2015-08-16
        • 1970-01-01
        • 2012-08-19
        • 2023-04-08
        • 2013-03-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多