Groovy - игнорировать дополнительные атрибуты на карте во время создания объекта

Есть ли способ сделать groovy игнорировать дополнительные атрибуты на карте во время создания объекта? Пример:

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

В этом примере groovy выбрасывает такое свойство: исключение по возрасту (очевидно, потому что возраст не определен в классе Banana). Не прибегая к ручному отображению только желаемых атрибутов из карты в конструктор класса Banana, есть ли способ сказать Банане игнорировать дополнительные атрибуты?

Я заметил, что классы домена Grails не страдают от этой проблемы, и мне бы хотелось, чтобы здесь было такое же поведение!

Спасибо за вашу помощь и совет!

Ответы

Ответ 1

К сожалению, нет встроенного способа сделать это в groovy. Grails делает это, создавая собственные конструкторы для объектов домена. Простым обходным путем является использование такого конструктора:

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

Ответ 2

Существует более простой способ справиться с этим случаем.

В вашем 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

Ответ 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 ответ (который является идеальным ответом :)), но вместо trait ваш класс может расширять 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.

Надеюсь, что это поможет,