2012-04-17 34 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

希望它能幫助,

相關問題