Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Blocker
-
Resolution: Fixed
-
Affects Version/s: 1.1.2
-
Fix Version/s: 1.2 final
-
Component/s: Controllers
-
Labels:None
Description
When binding two related domain objects in request with a command object, the following exception is thrown. Note that this also completely breaks scaffold CRUD with one-to-many relationships.
{{org.codehaus.groovy.grails.web.servlet.mvc.exceptions.ControllerExecutionException: Error occurred creating command object.
....
....
Caused by: java.lang.ClassCastException: B$_clinit_closure1 cannot be cast to java.util.Map
at org.codehaus.groovy.grails.web.binding.GrailsDataBinder.getConstrainedPropertyForPropertyValue(GrailsDataBinder.java:309)
at org.codehaus.groovy.grails.web.binding.GrailsDataBinder.filterBlankValuesWhenTargetIsNullable(GrailsDataBinder.java:291)
at org.codehaus.groovy.grails.web.binding.GrailsDataBinder.doBind(GrailsDataBinder.java:280)
at org.codehaus.groovy.grails.web.binding.GrailsDataBinder.bindWithRequestAndPropertyValues(GrailsDataBinder.java:269)
at org.codehaus.groovy.grails.web.binding.GrailsDataBinder.bind(GrailsDataBinder.java:234)
at org.codehaus.groovy.grails.web.binding.DataBindingUtils.bindObjectToDomainInstance(DataBindingUtils.java:148)
at org.codehaus.groovy.grails.web.binding.DataBindingUtils.bindObjectToInstance(DataBindingUtils.java:125)
at org.codehaus.groovy.grails.web.metaclass.BindDynamicMethod.invoke(BindDynamicMethod.java:97)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSite.invoke(PojoMetaMethodSite.java:188)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
at org.codehaus.groovy.grails.plugins.web.ControllersGrailsPlugin$_closure3_closure49.doCall(ControllersGrailsPlugin.groovy:262)
... 72 more }}
The class cast exception seems to come from one of the domain objects contraints clause being returned in GrailsDataBinder as a closure instead of a Map. I think it is because GroovyAwareJavassistLazyInitializer does not list the constraints closure in its filtered methods list but I could be wrong.
I've put this as Blocker because the problem renders many applications unusable. And the migration to 1.1.2 from 1.1.1 is nearly mandatory due to the transactional problems affecting 1.1.1.
There are two nabble discussions about the problem :
http://old.nabble.com/Binding-two-domain-objects-in-1.1.2-ts26577019.html
http://old.nabble.com/Grails-1.1.2%3A-Problem-binding-one-to-many-data-ts26561540.html
Julien Faissolle
-
Hide
- Problem-bug-report-30112009.zip
- 01/Dec/09 8:16 AM
- 16 kB
- Julien Faissolle
-
- grails-app/conf/BootStrap.groovy 0.1 kB
- grails-app/conf/Config.groovy 3 kB
- grails-app/conf/DataSource.groovy 0.6 kB
- grails-app/conf/UrlMappings.groovy 0.2 kB
- grails-app/conf/spring/resources.groovy 0.0 kB
- grails-app/.../ProblemController.groovy 0.1 kB
- grails-app/domain/A.groovy 0.1 kB
- grails-app/domain/B.groovy 0.0 kB
- grails-app/i18n/messages.properties 3 kB
- grails-app/i18n/messages_de.properties 3 kB
- grails-app/i18n/messages_es.properties 3 kB
- grails-app/i18n/messages_fr.properties 2 kB
- grails-app/i18n/messages_it.properties 2 kB
- grails-app/i18n/messages_ja.properties 2 kB
- grails-app/i18n/messages_nl.properties 3 kB
- grails-app/.../messages_pt_BR.properties 3 kB
- grails-app/i18n/messages_ru.properties 4 kB
- grails-app/i18n/messages_th.properties 5 kB
- grails-app/.../messages_zh_CN.properties 2 kB
- grails-app/views/error.gsp 2 kB
- grails-app/views/index.gsp 0.9 kB
- grails-app/views/layouts/main.gsp 0.7 kB
- test/unit/AControllerTests.groovy 0.2 kB
- test/unit/ATests.groovy 0.2 kB
- test/unit/BControllerTests.groovy 0.2 kB
- test/unit/BTests.groovy 0.2 kB
- test/unit/ProblemControllerTests.groovy 0.2 kB
Issue Links
- is duplicated by
-
GRAILS-5468
Grails 1.1.2 breaks update action on a domain class with a relationship to another domain class which has a constraints block.
-
Activity
- All
- Comments
- Work Log
- History
- Activity
- Git Commits
For the moment
grails install-plugin hibernate 1.1.3-SNAPSHOT
Fixes the problem
Thanks a lot for the quick answer but your patch creates a new problem in my application. If in a form, the id of a bound object is not provided (e.g. in a select combo, no choice is made) there is an exception :
org.codehaus.groovy.grails.web.servlet.mvc.exceptions.ControllerExecutionException: Error occurred creating command object.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:77)
at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:107)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:204)
at org.codehaus.groovy.grails.plugins.web.ControllersGrailsPlugin$_closure3_closure49.doCall(ControllersGrailsPlugin.groovy:271)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:151)
at org.codehaus.groovy.grails.plugins.web.ControllersGrailsPlugin$_closure3_closure49.call(ControllersGrailsPlugin.groovy)
at groovy.lang.Closure.call(Closure.java:274)
at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleAction(SimpleGrailsControllerHelper.java:368)
at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.executeAction(SimpleGrailsControllerHelper.java:243)
at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleURI(SimpleGrailsControllerHelper.java:203)
at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleURI(SimpleGrailsControllerHelper.java:138)
at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController.handleRequest(SimpleGrailsController.java:88)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet.doDispatch(GrailsDispatcherServlet.java:264)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1124)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:70)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:70)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:70)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:361)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:334)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)
at org.codehaus.groovy.grails.web.util.WebUtils.forwardRequestForUrlMappingInfo(WebUtils.java:293)
at org.codehaus.groovy.grails.web.util.WebUtils.forwardRequestForUrlMappingInfo(WebUtils.java:269)
at org.codehaus.groovy.grails.web.util.WebUtils.forwardRequestForUrlMappingInfo(WebUtils.java:261)
at org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter.doFilterInternal(UrlMappingsFilter.java:181)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)
at org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter.obtainContent(GrailsPageFilter.java:221)
at org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter.doFilter(GrailsPageFilter.java:126)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)
at org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter.doFilterInternal(GrailsReloadServletFilter.java:101)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)
at org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:65)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:361)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:534)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:864)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:533)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:207)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:403)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:522)
Caused by: java.lang.IllegalArgumentException: id to load is required for loading
at HibernateGrailsPlugin$_closure1_closure3.doCall(HibernateGrailsPlugin.groovy:60)
In order for my forms to work I had to modify the code in HibernateGrailsPlugin to add a conditional test on id
Thanks for the quick patch Graeme, this worked for me.
Although my issue was slightly different.
org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.ClassCastException: nz.co.waterforce.AssetType$_clinit_closure1 cannot be cast to java.util.Map
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:92)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1062)
at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:926)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:893)
at groovy.lang.Closure.call(Closure.java:279)
at groovy.lang.Closure.call(Closure.java:274)
at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleAction(SimpleGrailsControllerHelper.java:368)
at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.executeAction(SimpleGrailsControllerHelper.java:243)
at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleURI(SimpleGrailsControllerHelper.java:203)
at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleURI(SimpleGrailsControllerHelper.java:138)
at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController.handleRequest(SimpleGrailsController.java:88)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet.doDispatch(GrailsDispatcherServlet.java:264)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
@Julien Faissolle perhaps you could provide a default id or bind the current id to the combo box using the value attribute of the g:select tag.
The form submission (well the called action) that this patch fixes for me has a combo box.
Basically my combo box will always have an id bound (note the value attribute).
<g:select name="assetType.id" from="$
" optionKey="id" value="$
{assetInstance?.assetType?.id}" />
This may not help you, I just thought it might be worth a mention.
I have this problem too. Upgrading to hibernate 1.1.3-SNAPSHOT fixed the problem on one domain class but not on another.
2009-12-02 12:02:54,389 [http-8080-4] ERROR errors.GrailsExceptionResolver - java.lang.ClassCastException: Invoice$_clinit_closure1 cannot be cast to java.util.Map
org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.ClassCastException: Invoice$_clinit_closure1 cannot be cast to java.util.Map
My parameters look like this...
[billPhone:, billZip:8020, billCountryCode:US, invoice.code:0000, status:[id:2], invoice:[code:0000], billFirstName:Mr, _informUser:, statusText:, _action_Update:Update, billSurname:Williams, billCity:Graz, id:111639, action:index, controller:purchase, status.id:2, billLine1:Josefigasse 1, notes:, billLine2:, billState:]
The bootstrap workaround didn't work in this case either.
After adding the following to my form I managed to get around the error...
<g:hiddenField name="invoice.id" value="$
{purchase.invoice.id }" />
What works completely for me : reverting to hiebrnate 1.1.2 and putting the following in BootStrap
private static convertToType(value, targetType) {
SimpleTypeConverter typeConverter = new SimpleTypeConverter()
if (value != null && !targetType.isAssignableFrom(value.class)) {
if (value instanceof Number && Long.class.equals(targetType)) {
value = value.toLong()
}
else {
try {
value = typeConverter.convertIfNecessary(value, targetType)
} catch (org.springframework.beans.TypeMismatchException e) {
// ignore
};
}
}
return value
}
def init = { servletContext ->
//---------------------------------------------------------------------
// FIX BUG GRAILS-5445
//---------------------------------------------------------------------
def ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext)
if(ctx.containsBean("sessionFactory")) {
def sf = ctx.getBean("sessionFactory")
def template = new HibernateTemplate(sf)
for(d in ctx.getBean("grailsApplication").domainClasses) {
def domain = d
def identityType = domain.identifier.type
domain.clazz.metaClass.static.get = { Serializable id ->
id = convertToType(id, identityType)
def obj = id ? template.get(domain.clazz,id) : null
if(obj && obj instanceof org.hibernate.proxy.HibernateProxy) {
obj = obj.getHibernateLazyInitializer().implementation
}
return obj
}
}
}
...
This is identical to the code shipped in hibernate 1.1.3-SNAPSHOT with the difference only being the test on id after id = convertToType(id, identityType).
@Sean Tindale : in my case (fairly common I think), I am building a search filter on various related domain objects. Some or all of the combo boxes can be left without a value selected meaning the filter does not apply.
Thanks Julien for the patch. I needed also to add these import statements:
import org.springframework.beans.SimpleTypeConverter
import org.springframework.orm.hibernate3.HibernateTemplate
import org.springframework.web.context.support.WebApplicationContextUtils
can someone confirm for me that I'm getting those classes from the correct packages, for Grails 1.1.2?
- dan
closing this now since the fix is applied to the hibernate plugin
Workaround is to put this into BootStrap.groovy:
Will provide an updated hibernate plugin with the above fix in shortly