无法获得Grails ObjectMarshaller <json>的实现</json>

时间:2014-12-26 16:18:45

标签: json grails

我试图在Grails中实现自定义marshaller。这是编组人员:

class AdultPlanningMarshaller implements ObjectMarshaller<JSON> {
    boolean supports(Object theObject)
    {
        return theObject instanceof AdultPlanning
    }

    void marshalObject(Object theObject, JSON theConverter)
    {
        AdultPlanning adult = (AdultPlanning)theObject

        JSONWriter writer = theConverter.getWriter()

        writer.object()

        writer.key('id').value(adult.id)
        ...    
        writer.endObject()
    }
}

我在bootstrap.groovy中注册它,当我运行集成测试时,supports方法正确触发,并使用正确的对象和JSON对象调用marshalObject方法。

当我点击:

writer.object()

调用,抛出异常:

org.codehaus.groovy.grails.web.json.JSONException: Misplaced object: expected mode of INIT, OBJECT or ARRAY but was DONE

所以看起来作家已经完成了一些事情,但我不知道是什么。

关于JSON marshallers并没有很多关于JSON marshallers的文档,但是我认为我已经做到了这一点,但它确实无法正常工作。任何提示都将不胜感激。

使用调试器的进一步工作似乎表明对象编组器被调用了两次,尽管出于某种原因断点仅发生在第二次调用上。第一次通过它似乎工作正常,因为我通过theConverter.getWriter()得到的JSONWriter断点DOES工作时正确编组了对象的JSON。这是第二次调用,因为对象已被编组并且JSONWriter不再位于&#34; init&#34;州。现在没有什么可以说出这两个电话之间的区别,但是为什么要把两个电话调用两次?

根据要求,这是控制器。它是被触发的节目动作:

class PrimaryController extends RestfulController  implements AlwaysRenderJsonException {

    def springSecurityService
    def familyService

    static responseFormats = ['json']

    PrimaryController() {
        /*
         * Tell the base class the name of the resource under management.
         */

        super(Primary)
    }

    @Override
    protected Primary createResource() {
        //def instance = super.createResource()
        //TODO: Should be able to run the above line but there is an issue GRAILS-10411 that prevents it.
        // Code from parent is below, as soon as the jira is fixed, remove the following lines:

        Primary instance = resource.newInstance()
        bindData instance, this.getObjectToBind()

        //Code from super ends here

        def family = familyService.safeGetFamily(params.long('familyId'))

        familyService.addAdultToFamily(instance, family)    // Add the primary member to the family.

        return instance
    }

    /**
     * Deletes a resource for the given id
     * @param id The id
     */

    @Override
    def delete() {
        if(handleReadOnly()) {
            return
        }

        Child instance = queryForResource(params.id)
        if (instance == null) {
            notFound()
            return
        }

        /*
         * Because of the multiple belongsTo relationships of events, you have to get rid of all
         * the events and make the profiles consistent BEFORE deleting the person instance.
         */

        instance.removePerson()

        request.withFormat {
            '*'{ render status: NO_CONTENT } // NO CONTENT STATUS CODE
        }
    }

    @Override
    protected List<Primary> listAllResources(Map params) {
        if (params.familyId == null)
        {
            throw new ESPException("params.familyId may not be null")
        }

        def user = springSecurityService.loadCurrentUser()

        return \
            AdultPlanning.where {
                family.id == params.familyId \
                && family.user == user \
                && typeOfPerson == PeopleTypeEnum.PRIMARY
            }.list()
    }

    @Override
    protected Primary queryForResource(Serializable id) {
        def inst = familyService.safeGetAdult(Long.parseLong(id), params.long('familyId'))

        /*
         * It was safe to access the requested id, but the requested id may NOT be a primary
         * so we need to check.
         */

        return (inst instanceof Primary ? inst : null)
    }

    /**
     * Show the primary for the specified family.
     *
     * @return
     */

    @Override
    def show() {
        Primary primary = familyService.safeGetFamily(params.long('familyId'))?.primary

        respond primary
    }
}

触发它的集成测试:

void "We should be able to show a primary."() {
    given:
    family.addToAdults(new Primary(firstName: "Barney"))
    family.save()
    family.adults.each { it.save() }

    when:
    controller.response.reset()
    resetParameters(controller.params, [familyId: family.id])
    controller.request.method = 'GET'
    controller.show()

    then:
    1 * mSpringSecurityService.loadCurrentUser() >> user
    controller.response.json
    controller.response.json.firstName == "Barney"
}

3 个答案:

答案 0 :(得分:2)

嗯,这很令人尴尬。

我使用IntelliJ作为我的Java / Groovy IDE。我今天早上做了一件与工作有关的事情并退出了IntelliJ。当我重新启动IntelliJ时,上面描述的完全可重现的问题不再发生,并且在所有情况下都会生成相应的JSON。

所以似乎IntelliJ状态以某种方式被破坏并且重新启动将其清除。

问题解决了。

我想。

感谢您的帮助/建议。

答案 1 :(得分:1)

正如OP所提到的,由于IntelliJ:

,可以触发此错误

org.codehaus.groovy.grails.web.json.JSONException: Misplaced object: expected mode of INIT, OBJECT or ARRAY but was DONE

实际上,在调试marshaller(例如)时,IntelliJ会显示&#34; toString()&#34;变量的变量,导致模式从INIT变为DONE

您可能希望在遇到此问题时删除断点;)

答案 2 :(得分:0)

这样做的唯一原因可能是你已经为某些嵌套对象或数组响应启动了writer.object()但是错过了写writer.endObject()或者你已经写了两次。

因此请仔细检查所有写入对象的自定义编组器。

参考:https://github.com/grails/grails-core/blob/65b42b66821b32d4efb3a229da99691a00575d60/grails-web-common/src/main/groovy/org/grails/web/json/JSONWriter.java#L258

希望这有帮助!

谢谢,
SA