Grails fails to start with cryptic error
I ran into a coding error in a Grails (1.0.4, this does not appear to be an issue in 1.1.1) app recently that proved very hard to diagnose. It turned out to be a simple coding error, just hard to spot syntax.
After a simple refactor by someone else I was asked to help figure out why the app would no longer run. We got a error like:
Failed startup of context org.mortbay.jetty.webapp.WebAppContext@59139826{/ClosureTest,/Users/ahahn/devel/src/test/ClosureTest/web-app}
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pluginManager' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.RuntimeException: Unable to locate constructor with Class parameter for class org.codehaus.groovy.grails.commons.DefaultGrailsControllerClass
at java.security.AccessController.doPrivileged(Native Method)
at RunApp_groovy$_run_closure2_closure7.doCall(RunApp_groovy:67)
at RunApp_groovy$_run_closure2_closure7.doCall(RunApp_groovy)
at Init_groovy$_run_closure6.doCall(Init_groovy:131)
at RunApp_groovy$_run_closure2.doCall(RunApp_groovy:66)
at RunApp_groovy$_run_closure2.doCall(RunApp_groovy)
at RunApp_groovy$_run_closure1.doCall(RunApp_groovy:57)
at RunApp_groovy$_run_closure1.doCall(RunApp_groovy)
at gant.Gant.dispatch(Gant.groovy:271)
at gant.Gant.this$2$dispatch(Gant.groovy)
at gant.Gant.invokeMethod(Gant.groovy)
at gant.Gant.processTargets(Gant.groovy:436)
at gant.Gant.processArgs(Gant.groovy:372)
Caused by: java.lang.RuntimeException: Unable to locate constructor with Class parameter for class org.codehaus.groovy.grails.commons.DefaultGrailsControllerClass
... 13 more
Caused by: java.lang.reflect.InvocationTargetException
... 13 more
Caused by: org.codehaus.groovy.grails.exceptions.NewInstanceCreationException: Could not create a new instance of class [TestController]!
... 13 more
Caused by: java.lang.VerifyError: (class: TestController$_closure2, method: doCall signature: (Ljava/lang/Object;)Ljava/lang/Object;) Incompatible argument to function
at TestController.(TestController.groovy)
... 13 more
2009-05-25 11:01:25.026::WARN: Nested in org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pluginManager' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.RuntimeException: Unable to locate constructor with Class parameter for class org.codehaus.groovy.grails.commons.DefaultGrailsControllerClass:
java.lang.VerifyError: (class: TestController$_closure2, method: doCall signature: (Ljava/lang/Object;)Ljava/lang/Object;) Incompatible argument to function
at TestController.(TestController.groovy)
at java.security.AccessController.doPrivileged(Native Method)
at RunApp_groovy$_run_closure2_closure7.doCall(RunApp_groovy:67)
at RunApp_groovy$_run_closure2_closure7.doCall(RunApp_groovy)
at Init_groovy$_run_closure6.doCall(Init_groovy:131)
at RunApp_groovy$_run_closure2.doCall(RunApp_groovy:66)
at RunApp_groovy$_run_closure2.doCall(RunApp_groovy)
at RunApp_groovy$_run_closure1.doCall(RunApp_groovy:57)
at RunApp_groovy$_run_closure1.doCall(RunApp_groovy)
at gant.Gant.dispatch(Gant.groovy:271)
at gant.Gant.this$2$dispatch(Gant.groovy)
at gant.Gant.invokeMethod(Gant.groovy)
at gant.Gant.processTargets(Gant.groovy:436)
at gant.Gant.processArgs(Gant.groovy:372)
Which I could trace to the TestController code:
def list = Test.list( params )
def testMaps = []
if(list) {
list.each {test ->
if(test.bool) {
testMaps << [
foo: it.foo,
bar: "Bar ${it.bar}"
]
}
}
}
Spot it yet? No really, spot it yet? It is simply a case of an incomplete refactor, the each closure was changed to have a named parameter ‘test’ but not all code in the body was refactored. Most of the references to the current object in the iteration still used the default parameter ‘it’. So what you would expect to be a run time error actual blows up at start up.
Just in case, here it the working code:
def list = Test.list( params )
def testMaps = []
if(list) {
list.each {test ->
if(test.bool) {
testMaps << [
foo: test.foo,
bar: "Bar ${test.bar}"
]
}
}
}