Grails getProperties method does not always return properties in the correct order

妖精的绣舞 提交于 2019-12-13 03:44:10

问题


I have a class that looks like this:

class Foo {
    name
    description

    static constraints = {
        name()
        description()
    }
}

I want to add display instances of my class in a Flexigrid. When data is sent to a flexigrid it needs to be in a format like JSON or XML... I have chosen JSON. Flexigrid expects JSON arrays it receives to have the following format:

{
    "page": "1",
    "total": "1",
    "rows": [
        {
            "id": "1",
            "cell": [
                "1",
                "The name of Foo 1",
                "The description of Foo 1"
            ]
        },
        {
            "id": "2",
            "cell": [
                "2",
                "The name of Foo 2",
                "The description of Foo 2"
            ]
        }
    ]
}

To get my Foo objects into this format I do something similar to this:

def foos = Foo.getAll( 1, 2 )

def results = [:]
results[ "page" ] = params.page
results[ "total" ] = foos.size()
results[ "rows" ] = []

for( foo in foos ) {
    def cell = []
    cell.add( foo.id )

    foo.getProperties().each() { key, value -> // Sometimes get foo.getProperties().each() returns foo.description then foo.name instead of foo.name then foo.description as desired.
        cell.add( value.toString() )
    }

    results[ "rows" ].add( [ "id": foo.id, "cell": cell ] )
}

render results as JSON

The problem is that every once in a while foo.getProperties().each() returns foo.description then foo.name resulting in foo.description being put in the name column of my flexigrid and foo.name being put in the description column of my flexigrid for a specific row.

I tried specifying constraints in the Foo domain class so the getProperties would return in the correct order, but it didn't work. How can I make sure getProperties returns properties in a predictable order?

This is how I fixed this issuse:

def items = Foo.getAll()

for( item in items ) {
    def cell = []
    cell.add( item.id )
    Foo.constraints.each() { key, value ->
        def itemValue = item.getProperty( key )
        if( !( itemValue instanceof Collection ) ) {
            cell.add( itemValue.toString() )
        }
    }
}

So Foo.constraints gets a map of constraints where each constraint is an instance of Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry. After testing I have found this map always returns my Foo static constraints in the order I entered them (also confirmed by Ian). Now only the properties of the item which are in Foo.constraints will be added to the cell for flexigrid.


回答1:


I don't think foo.getProperties() guarantees anything about the ordering. But Foo.constraints is overridden at runtime to return not the original closure, but a Map of ConstrainedProperty objects and the keys in this map are guaranteed to be in the same order as the constraints closure (this is how scaffolding is able to use the constraints ordering to define the order in which fields are presented in the scaffolded views). So you could do something like

def props = [:] // [:] declares a LinkedHashMap, so order-preserving
Foo.constraints.each { k, v ->
  props[k] = foo."${k}"
}



回答2:


foo.getProperties().sort() or if there's no good way to sort the properties in the order you need, you could always define the order of the properties yourself in a list to iterate over.

def properties = ['name', 'description']
properties.each {
     cell.add(foo."$it")
}


来源:https://stackoverflow.com/questions/11150476/grails-getproperties-method-does-not-always-return-properties-in-the-correct-ord

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!