错误errors.GrailsExceptionResolver - JSONException错位的endArray

时间:2015-09-25 18:05:39

标签: json grails groovy

我使用Grails和AngularJS制作一个RESTful twitter / facebook克隆,所以它是一个标准用户可以发帖,用户可以喜欢发帖,用户也可以关注其他用户。

我正在使用JSON对象marshallers,以便域类的hasManybelongsTo的属性将在JSON中呈现。

我已在UserPost域之间插入了相似功能的必要关系,以及我在Bootstrap.groovy中实施这些关系时是否发送GET请求到api/posts/一切正常,但问题是当我使用按钮实现它们时。 此按钮向PUT发送api/posts/:id请求,这将转到我update()的{​​{1}}方法。类似的内容正在插入到数据库中,但如果我再向PostController发送另一个GET请求,则会收到此错误

api/posts

这些是我的代码

User.groovy

....Error
|
2015-09-26 00:54:35,986 [http-bio-8090-exec-9] ERROR 
errors.GrailsExceptionResolver 
 - JSONException occurred when processing request: [GET] /restsocnet/api/posts
Misplaced endArray.. Stacktrace follows:
Message: Misplaced endArray.
    Line | Method
->>  202 | value              in grails.converters.JSON
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|    162 | convertAnother     in     ''
|    202 | value . . . . . .  in     ''
|    162 | convertAnother     in     ''
|    202 | value . . . . . .  in     ''
|    162 | convertAnother     in     ''
|    202 | value . . . . . .  in     ''
|    162 | convertAnother     in     ''
|    202 | value . . . . . .  in     ''
|    162 | convertAnother     in     ''
|    202 | value . . . . . .  in     ''
|    162 | convertAnother     in     ''
|    202 | value . . . . . .  in     ''
|    162 | convertAnother     in     ''
|    202 | value . . . . . .  in     ''
|    162 | convertAnother     in     ''
|    202 | value . . . . . .  in     ''
|    134 | render             in     ''
|    150 | render . . . . . . in     ''
|     19 | index              in com.patrickjuen.restsocnet.PostController
|    198 | doFilter . . . . . in grails.plugin.cache.web.filter.PageFragmentCachingFilter
|     63 | doFilter           in grails.plugin.cache.web.filter.AbstractFilter
|    118 | processFilterChain in grails.plugin.springsecurity.rest.RestTokenValidationFilter
|     84 | doFilter           in     ''
|     53 | doFilter . . . . . in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
|    143 | doFilter           in grails.plugin.springsecurity.rest.RestAuthenticationFilter
|     62 | doFilter . . . . . in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
|     82 | doFilter           in com.brandseye.cors.CorsFilter
|   1142 | runWorker . . . .  in java.util.concurrent.ThreadPoolExecutor
|    617 | run                in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run . . . . . . .  in java.lang.Thread

Post.groovy

package com.patrickjuen.restsocnet

class User implements Serializable {

    private static final long serialVersionUID = 1

    transient springSecurityService

    String username
    String password
    boolean enabled = true
    boolean accountExpired
    boolean accountLocked
    boolean passwordExpired
    static hasMany = [posts: Post, likedPost: Post]
    static mappedBy = [posts: "user"]


    User(String username, String password) {
        this()
        this.username = username
        this.password = password
    }

    @Override
    int hashCode() {
        username?.hashCode() ?: 0
    }

    @Override
    boolean equals(other) {
        is(other) || (other instanceof User && other.username == username)
    }

    @Override
    String toString() {
        username
    }

    Set<Role> getAuthorities() {
        UserRole.findAllByUser(this)*.role
    }

    def beforeInsert() {
        encodePassword()
    }

    def beforeUpdate() {
        if (isDirty('password')) {
            encodePassword()
        }
    }

    protected void encodePassword() {
        password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
    }

    static transients = ['springSecurityService']

    static constraints = {
        username blank: false, unique: true
        password blank: false
        likedPost nullable: true
    }

    static mapping = {
        password column: '`password`'
        posts lazy: false, sort: 'dateCreated', order: 'desc'
        likedPost lazy: false

    }
}



package com.patrickjuen.restsocnet

import grails.converters.JSON

//import grails.plugin.springsecurity.annotation.Secured
import org.springframework.security.access.annotation.Secured


@Secured(['isFullyAuthenticated()'])
class PostController {

    static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]


    def springSecurityService

    def index() {
        render Post.list(sort: "dateCreated", order: "desc") as JSON
    }

    def save(){
        def newPost = new Post(request.JSON)
        if(!newPost.hasErrors()){
            def currentUser = User.get(springSecurityService.principal.id)
            println currentUser
            newPost.user = currentUser
            newPost.save(failOnError: true)

//            currentUser.addToPosts(newPost)
            render (['success': true] as JSON)
        }
    }

    def show(){
        def post = Post.get(params.id)
        render post as JSON
    }

    def update(){
        def post = Post.findById(params.id)
        if(!post.hasErrors()){
            def currentUser = User.get(springSecurityService.principal.id)
            post.addToLikers(currentUser)
            post.save(flush: true)
            render(['success': true] as JSON)
        }
    }
}

BootStrap.groovy中

package com.patrickjuen.restsocnet

class Post {

    String content
    Date dateCreated
    User user
    static belongsTo = User
    static hasMany = [likers: User]
//    static mappedBy = [likers: "likedPost"]
    static constraints = {
        likers nullable: true
    }
    static mapping = {
        likers lazy: false
    }
}

PostController.groovy

import com.patrickjuen.restsocnet.Post
import com.patrickjuen.restsocnet.Role
import com.patrickjuen.restsocnet.User
import com.patrickjuen.restsocnet.UserRole
import grails.converters.JSON

class BootStrap {

    def init = { servletContext ->

        JSON.registerObjectMarshaller(User) {
            def returnArray = [:]
            returnArray['id'] = it.id
            returnArray['username'] = it.username
            returnArray['posts'] = it.posts
            return returnArray
        }
        JSON.registerObjectMarshaller(Post) {
            def returnArray = [:]
            returnArray['id'] = it.id
            returnArray['content'] = it.content
            returnArray['dateCreated'] = it.dateCreated
            returnArray['user'] = it.user
            returnArray['likers'] = it.likers
            return returnArray
        }


        def role = new Role(authority: "ROLE_USER")
        def user1 = new User(username: "user1", password: "password")
        def user2 = new User(username: "user2", password: "password")
        role.save()
        user1.save()
        user2.save()

        def post1 = new Post(content: "new post number 1")
        def post2 = new Post(content: "new post number 2")
        def post3 = new Post(content: "one more ")
        def post4 = new Post(content: "i am user2 guys hehehe")
        post1.save()
        post2.save()
        post3.save()
        post4.save()

        user1.addToPosts(post1)
        user1.addToPosts(post2)
        user1.addToPosts(post3)
        user2.addToPosts(post4)
        post2.addToLikers(user2)
        post2.addToLikers(user1)
        post1.addToLikers(user1)

        UserRole.create(user1, role, true)
        UserRole.create(user2, role, true)
    }
    def destroy = {
    }
}

我尝试删除JSON对象marshallers并且它不再发出错误但我将无法访问package com.patrickjuen.restsocnet import grails.converters.JSON //import grails.plugin.springsecurity.annotation.Secured import org.springframework.security.access.annotation.Secured @Secured(['isFullyAuthenticated()']) class PostController { static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"] def springSecurityService def index() { render Post.list(sort: "dateCreated", order: "desc") as JSON } def save(){ def newPost = new Post(request.JSON) if(!newPost.hasErrors()){ def currentUser = User.get(springSecurityService.principal.id) println currentUser newPost.user = currentUser newPost.save(failOnError: true) // currentUser.addToPosts(newPost) render (['success': true] as JSON) } } def show(){ def post = Post.get(params.id) render post as JSON } def update(){ def post = Post.findById(params.id) if(!post.hasErrors()){ def currentUser = User.get(springSecurityService.principal.id) post.addToLikers(currentUser) post.save(flush: true) render(['success': true] as JSON) } } } 的属性。所以我猜主要的问题是JSON对象marshallers。我错误地执行了它们吗?或者是否有使用JSON对象marshallers的替代方法?但是,当我在hasMany中实现它时,它再次正常工作 此外,我尝试将Bootstrap.groovy更改为仅post.save(flush:true)它没有发出错误,但未在数据库中保存。

以防您对正在呈现的JSON感兴趣。 这是对post.save()

GET请求

没有JSON对象marshallers

api/posts/

使用JSON对象marshallers

[
  {
    "class": "com.patrickjuen.restsocnet.Post",
    "id": 4,
    "content": "i am user2 guys hehehe",
    "dateCreated": "2015-09-25T17:39:10Z",
    "likers": [],
    "user": {
      "class": "com.patrickjuen.restsocnet.User",
      "id": 2
    }
  },
  {
    "class": "com.patrickjuen.restsocnet.Post",
    "id": 3,
    "content": "one more",
    "dateCreated": "2015-09-25T17:39:10Z",
    "likers": [],
    "user": {
      "class": "com.patrickjuen.restsocnet.User",
      "id": 1
    }
  },
  {
    "class": "com.patrickjuen.restsocnet.Post",
    "id": 2,
    "content": "new post number 2",
    "dateCreated": "2015-09-25T17:39:10Z",
    "likers": [
      {
        "class": "com.patrickjuen.restsocnet.User",
        "id": 1
      },
      {
        "class": "com.patrickjuen.restsocnet.User",
        "id": 2
      }
    ],
    "user": {
      "class": "com.patrickjuen.restsocnet.User",
      "id": 1
    }
  },
  {
    "class": "com.patrickjuen.restsocnet.Post",
    "id": 1,
    "content": "new post number 1",
    "dateCreated": "2015-09-25T17:39:10Z",
    "likers": [
      {
        "class": "com.patrickjuen.restsocnet.User",
        "id": 1
      }
    ],
    "user": {
      "class": "com.patrickjuen.restsocnet.User",
      "id": 1
    }
  }
]

1 个答案:

答案 0 :(得分:1)

我刚刚找到了解决方案。此代码只需插入Config.groovy

即可

grails.converters.json.circular.reference.behaviour = "INSERT_NULL"

我在本文http://manbuildswebsite.com/2010/02/15/rendering-json-in-grails-part-3-customise-your-json-with-object-marshallers/

的其中一条评论中看到了这一点