2014-12-26 58 views
1

我想在Grails中實現一個自定義編組器。這裏的編組:無法獲得Grails ObjectMarshaller的實現<JSON>工作

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中,當我運行我的集成測試,正確的方法支持火災和marshalObject方法被調用合適的對象和JSON對象。

當我打的:

writer.object() 

電話,一個異常被拋出:

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

所以它看起來像筆者已經做了什麼事完成,但是我不知道是什麼。

JSON編組沒有太多的文檔,實例很薄弱,但我認爲我已經做到了這一點,但肯定無法正常工作。任何提示將不勝感激。

調試器的進一步工作似乎表明,對象編組器正在被調用兩次,儘管斷點僅在第二次調用中出於某種原因。第一次通過它似乎工作得很好,因爲當斷點確實工作時,我通過Converter.getWriter()獲得的JSONWriter正確地編組了對象的JSON。這是第二次調用,因爲對象已經被編組,並且JSONWriter不再處於「init」狀態。沒有什麼明顯可用來分辨這兩個電話之間的區別,但爲什麼這個編組被稱爲兩次?

按照要求,這裏是控制器。這是一個的被觸發show動作:觸發它

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" 
} 
+0

這應該可行,您正在使用哪個grails版本?你可以發佈控制器操作代碼,你正在響應實例。 –

+0

使用Grails 2.4.4 – user1416192

回答

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

+0

自定義編組器在功能上全部提供。沒有丟失的endObject,沒有嵌套的數組。 – user1416192

1

那麼,這是令人尷尬的。

我使用IntelliJ作爲我的Java/Groovy IDE。我今天早上做了一件與工作有關的事情,並退出了IntelliJ。當我重新啓動IntelliJ時,上述問題已經完全可以重現,不再發生,並且在任何情況下都生成了適當的JSON。

因此,似乎IntelliJ狀態不知何故被損壞,重新啓動清除它。

問題解決。

我想。

感謝您的幫助/建議。

0

如OP所提到的,可能由於的IntelliJ來觸發這樣的錯誤:

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

事實上,調試編組時(例如),的IntelliJ顯示可變的 「的toString()」,其導致模式從INIT更改爲DONE

您可能希望在面臨此問題時移除斷點;)