Переборе свойств объекта в Groovy?

Я создал класс, который позволяет результирующему объекту иметь произвольные свойства, добавленные к нему. Класс также имеет некоторые предопределенные свойства. В методе класса я хочу иметь возможность перебирать все свойства, принадлежащие экземпляру объекта.

вот пример определения класса:

import groovy.json.*

class Foo {
    private Map props = [:]

    String bar = "baz"
    def myNumber = 42

    void propertyMissing(String name, Object value) {
        this.props[name] = value
    }

    def propertyMissing(String name) {
        return this.props[name]
    }

    def toJsonString() {
        def outObject = [:]

        // I want to do something like this
        this.properties.each { k, v ->
            if (this.isOwnProperty(k) && k != 'props') {
                outObject[k] = v
            }
        }

        outObject = outObject + this.props

        return JsonOutput.toJson(outObject)
        // Should return a string like:
        // {"bar":"baz", "myNumber":42, "someDynamicProperty":"value"}
        //
        // This string should not contain the "class" and "metaClass"
        // properties.
    }
}

есть ли способ сделать то, что я хочу сделать?

Edit: Одна из моих целей состоит в том, чтобы не нужно явно называть мой предопределенные свойства в toJsonString метод. Я хочу иметь возможность добавлять новые предопределенные свойства на более поздний срок без необходимости обновлять toJsonString метод.

Edit (24 Октября 2011):

принятый ответ дал мне необходимую информацию. Тем не менее, мне все еще требовалось назвать свойства, которые я не хочу включать в строку JSON. Расширение ответа немного решает эту проблему:

def outObject = Foo.declaredFields.findAll {
    // 'it' is a Field object returned by
    // http://download.oracle.com/javase/1,5,0/docs/api/java/lang/Class.html#getDeclaredFields()
    !it.synthetic &&
    it.getModifiers() != java.lang.reflect.Modifier.PRIVATE
}.collectEntries { v ->
    [ (v.name) : this[v.name] ]
}

для этого, чтобы работать, необходимо явно указать модификаторы для свойств класса. Это String bar = "baz" в моем примере должно быть public String bar = "baz" для того, чтобы он был включен в строку JSON.

2 ответов


есть такая возможность (при условии, что у меня есть правый конец палки); -)

class Foo {
    private Map props = [:]

    String bar = "baz"
    def myNumber = 42

    void propertyMissing(String name, Object value) {
        this.props[name] = value
    }

    def propertyMissing(String name) {
        return this.props[name]
    }

    def toJsonString() {
        def outObject = Foo.declaredFields.findAll { !it.synthetic && it.name != 'props' }.collectEntries { v ->
          [ (v.name):this[v.name] ]
        }
        outObject << props
        JsonOutput.toJson(outObject)
    }
}

если у вас нет Groovy 1.7.9+, то строки

        def outObject = Foo.declaredFields.findAll { !it.synthetic && it.name != 'props' }.collectEntries { v ->
          [ (v.name):this[v.name] ]
        }

заменить:

        def outObject = Foo.declaredFields.findAll { !it.synthetic && it.name != 'props' }.inject([:]) { m, v ->
          m << [ (v.name):this[v.name] ]
        }

и я верю, что он будет вести себя так же; то есть: если я делаю это:

def f = new Foo()
f.tim = 'yates'
println f.toJsonString()

выводит:

{"bar":"baz","myNumber":42,"tim":"yates"}

Если вы хотите придерживаться этой реализации, возможно переопределение getProperties включить карту недвижимости было бы проще всего.