嘗試
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 = {
}
}