尝试
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 = {
}
}