开发者

How to render complex JSON with Grails 1.2 dynamically?

开发者 https://www.devze.com 2022-12-20 07:13 出处:网络
I would like to render a complex type, using the JSON render method in Gra开发者_如何学JAVAils, similar to the JSON output below:

I would like to render a complex type, using the JSON render method in Gra开发者_如何学JAVAils, similar to the JSON output below:

{
  "authors": [{
    "id": 1,
    "name": "Author 1",
    "books": [{
      "id": 1,
      "name": "Book 1"
    }, {
      "id": 2,
      "name": "Book 2"
    }]
  }, {
    "id": 2,
    "name": "Author 2",
    "books": [{
      "id": 1,
      "name": "Book 1"
    }, {
      "id": 2,
      "name": "Book 2"
    }]
  }]
}

And I've tried doing this with the following code, where Author and Book are domain classes containing the properties id and name and where Author hasMany Books (association).

def results = Authors.list()
render(contentType:"text/json") {
  authors = array {
    for(a in results) {
      author id:a.id, name:a.name, books: array = {
        def bookresults = Book.findAllByAuthor(a)
        for(b in bookresults) {
          book id:b.id, name:b.name
        }
      }
    }
  }    
}

It works fine with authors alone, but not when I try to iterate through each author's books and render those as well, the code fail.

Any ideas?

Updated question with final code

Thanks to Dave's answer I ended up with the following code that works as expected:

def authors = []

for (a in Author.list()) {
  def books = []
  def author = [id:a.id, name:a.name, books:books]

  for (b in Book.findAllByAuthor(a)) {
    def book = [id:b.id, name:b.name]
    books << book
  }

  authors << author
}

def items = [authors:[authors]]
render items as JSON 


I find the JSON builder very difficult to use to get the desired results so I prefer to generate the results in maps and lists and then render those.

By having something like the following (warning: untested code!):

def results = []
Authors.list()?.each{ author ->
    def authorResult = [id:author.id, name:author.name]
    Book.findAllByAuthor(author)?.each { book ->
        authorResultput('books', [id:book.id, name:book.name])
    }
    results << authorResult
}
def authors = [authors: results]
render authors as JSON

I think you make the code easier to read and reuse and it should do what you want (my typos permitting).

If you're always going to render your authors and books in the same JSON format you might consider registering a custom JSON object marshaller in Bootstrap.groovy. In summary something like would work:

    JSON.registerObjectMarshaller(Author) {
        def returnArray = [:]
        returnArray['id'] = it.id
        returnArray['name'] = it.name
        return returnArray
    }

Also having a books property on your author would make things easier still!

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号