在Groovy中迭代对象自己的属性?

Jam*_*ers 6 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.
    }
}
Run Code Online (Sandbox Code Playgroud)

有办法做我想做的事吗?

编辑: 我的目标之一是不必在toJsonString方法中明确命名我的预定义属性.我希望能够在以后添加新的预定义属性,而不必记住更新toJsonString方法.

编辑(2011年10月24日):

接受的答案给了我所需的信息.但是,它仍然需要我命名我不希望包含在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] ]
}
Run Code Online (Sandbox Code Playgroud)

为此,您必须明确指定类属性的修饰符.这是String bar = "baz"在我的例子应该是public String bar = "baz"为了它被包含在JSON字符串.

tim*_*tes 7

有这种可能性(假设我有正确的结束);-)

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你没有Groovy 1.7.9+,那么这些行

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

应该替换为:

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

而且我相信它会表现得一样; 即:如果我这样做:

def f = new Foo()
f.tim = 'yates'
println f.toJsonString()
Run Code Online (Sandbox Code Playgroud)

打印出来:

{"bar":"baz","myNumber":42,"tim":"yates"}
Run Code Online (Sandbox Code Playgroud)