【问题标题】:Groovy - Ignore extra attributes in a map during object instantiationGroovy - 在对象实例化期间忽略地图中的额外属性
【发布时间】:2012-04-17 17:00:16
【问题描述】:

有没有办法让 groovy 在对象实例化期间忽略映射中的额外属性?示例:

class Banana{
    String name
}
def params = [name:'someGuy', age:13]
new Banana(params)

在本例中,groovy 抛出 No such property: age 异常(显然是因为在 Banana 类中未定义 age。无需手动将所需属性从 map 映射到 Banana 类的构造函数,就是有没有办法告诉 Banana 忽略额外的属性?

我注意到 Grails 域类不会遇到这个问题,我希望这里有同样的行为!

感谢您的帮助和建议!

【问题讨论】:

    标签: dictionary groovy constructor attributes


    【解决方案1】:

    有一种更简单的方法可以处理这种情况。

    在你的 bean 中,实现一个 trait

    trait IgnoreUnknownProperties {
        def propertyMissing(String name, value){
            // do nothing
        }
    }
    
    class Person implements IgnoreUnknownProperties {
        String name
    }
    
    map = ["name": "haha", "extra": "test"]
    Person p = new Person(map)
    
    println p.name
    

    【讨论】:

    • 我已经在 Groovy 控制台 (v2.4.8) 中成功使用了这种方法,但是当我尝试在我的 Groovy 项目中做同样的事情时,我得到一个 java.lang.VerifyError 抱怨 propertyMissing 的方法签名?!有人知道为什么吗?
    • 对于任何想知道为什么会这样的人,这绕过了初始错误 MissingPropertyException。在对象实例化期间,invokeMissingPropery() method 会自动抛出此异常。如文档中所述,此方法将调用propertyMissing(),如果未定义propertyMissing(),则抛出MissingProperty异常。
    【解决方案2】:

    不幸的是,在 groovy 中没有内置的方法可以做到这一点。 Grails 通过为域对象生成它自己的构造函数来做到这一点。一个简单的解决方法是使用这样的构造函数:

    Banana(Map map) {
        metaClass.setProperties(this, map.findAll { key, value -> this.hasProperty(key) })
    }
    

    【讨论】:

    • 显然,您必须确保您的 params 映射不包含键 classmetaClass,否则会出现异常/怪异 ;-)
    • 谢谢 - 我喜欢 grails 的这个功能,我希望它不是通过巧妙的技巧而是语言功能。那好吧。不过,您的解决方法应该可以解决问题,谢谢!
    【解决方案3】:

    如果所有属性都存在,另一种不会影响性能的方法:

    public static Banana valueOf(Map<String, Object> params) {
        try {
            return new Banana(source)
        } catch (MissingPropertyException e) {
            log.info(e.getMessage())
            source.remove(e.property)
            return valueOf(source)
        }
    }
    

    【讨论】:

      【解决方案4】:

      类似于@JiankuanXing 的答案(这是一个完美的答案:)),但你的类可以扩展Expando 并添加propertyMissing 方法,而不是使用trait

      class Banana extends Expando {
          String name
      
          def propertyMissing(name, value) {
              // nothing
          }
      }
      def params = [name:'someGuy', age:13]
      new Banana(params)
      

      trait 的使用可能更适合这种情况,因为它允许行为组合,您可以将trait 添加到所有需要它的类对象中。我只添加这个替代方案,因为Expando 可以使用自groovy 1.5 版本,而traitsgroovy 2.3 中引入。

      希望对你有帮助,

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-17
        • 2011-11-23
        • 2016-05-26
        • 1970-01-01
        • 2012-12-09
        相关资源
        最近更新 更多