如何在 controller action 方法參數中使用枚舉?

嘗試

controller 代碼如下:

def list(GuessType type, int max) {
}

報錯

Could not find matching constructor for: chess_lottery.enumeration.GuessType()
groovy.lang.GroovyRuntimeException: Could not find matching constructor for: chess_lottery.enumeration.GuessType()
	at grails.artefact.Controller$Trait$Helper.initializeCommandObject(Controller.groovy:425)
	at org.grails.testing.runtime.support.ActionSettingMethodHandler.invoke(ActionSettingMethodHandler.groovy:29)
	at chess_api.GuessControllerSpec.測試枚舉類型是否能正確綁定到action的參數(GuessControllerSpec.groovy:18)

搜索參考

  • https://stackoverflow.com/questions/7235183/data-binding-to-an-enum-on-a-command-in-grails
  • http://docs.grails.org/latest/ref/Controllers/bindData.html

需要研究 grails 的 data binding 實現。

代碼:
grails.artefact.Controller#initializeCommandObject

最後 grails 創建這個枚舉的代碼是這樣的:

grails.artefact.Controller#initializeCommandObject()

。。。
    } else if (requestMethod == HttpMethod.POST || !isDomainClass) {
        commandObjectInstance = type.newInstance()
    }
。。。

瞭解一下枚舉是否可以實例化?
https://stackoverflow.com/questions/16851377/instantiate-enum-class
答:不能調用構造函數來實例化一個枚舉,需要用 valueOf() 方法來獲取 一個已經存在的枚舉,因爲枚舉值在JVM中必須是唯一的。

結論

截止 Grails v4.0.3 版本,Controller 的 action 方法還不支持使用枚舉類型作爲參數進行 data binding。也就是說將枚舉作爲action的參數會導致拋出異常。

繞過方案:
在 action 參數中定義一個 int id 參數,用一個 command object 來進行參數綁定,然後自定義一個 set 方法,將 int id 轉換爲枚舉,如果轉換失敗則設置相應的 validation errors。

class ListGuessCommand implements Validateable {
    /**
     * 競猜類型,取值看 GuessType.id
     */
    int type
    /**
     * 最大記錄數
     */
    int max = 20
    /**
     * 自動根據 type 轉換而來
     */
    GuessType guessType

    def setType(int type){
        // 轉換爲枚舉
        guessType = GuessType.valueOf(type)
        if (!guessType){
            errors.rejectValue("type", "無法找到type對應的 GuessType 枚舉定義")
        }
    }
    static constraints = {
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章