2012-04-17 81 views
15

有没有办法在对象实例化过程中让groovy忽略地图中的额外属性?例如:Groovy - 在对象实例化过程中忽略地图中的额外属性

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

在此示例中,常规引发一个没有这样的属性:年龄异常(显然是因为年龄未在香蕉类中定义没有求助于仅手动映射从地图所需的属性给构造。香蕉类的,有没有办法告诉香蕉忽略额外的属性?

我注意到,Grails领域类不存在这个问题,我也喜欢这里的相同的行为!

感谢你的帮助和建议!

回答

10

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

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

很明显,你必须确保你的PARAMS映射不包含键'class'或'metaClass',或例外/怪事将接踵而至;-) – 2012-04-18 08:17:51

+0

谢谢你 - 我喜欢这个Grails的特性,我希望它不是通过巧妙的技巧,而是一种语言功能。好吧。你的解决方法应该可以做到这一点,谢谢! – Quad64Bit 2012-04-18 11:40:13

2

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

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) 
    } 
} 
11

还有一个更简单的处理这种情况的方式。

在你的bean,只实现一个特点

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 
+0

真正优雅的解决这个问题的方法。 – 2015-07-23 18:19:13

+0

我已经在Groovy控制台(v2.4.8)中成功地使用了这种方法,但是当我尝试在Groovy项目中做同样的事情时,我得到一个java.lang.VerifyError抱怨propertyMissing的方法签名?!有人知道为什么吗? – Emil 2017-03-28 10:48:08

1

类似@ JiankuanXing的回答(这是一个完美的答案:)),但不是使用trait类是否可以extends Expando并添加propertyMissing方法:

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版本,而traits被引入groovy 2.3

希望它能帮助,