Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: 2.0-RC1
-
Fix Version/s: 2.1-RC1
-
Component/s: Controllers
-
Labels:
Description
After upgrade from 1.3.7 to 2.0.0 RC1 i've got the following exception while using the command object validation feature:
java.lang.NoSuchMethodError: UserFormCommand.validate()Z
Obs.: It works after downgrade to 1.3.7.
The following is the code i used:
---> Controller
def create = { UserFormCommand cmd ->
if(cmd.validate()) {
User.withTransaction { status ->
User user = new User(name: params.name, email: params.email, password: params.password)
if (params.openId)
user.setEnabled(true)
user.setAccountLocked(false)
user.password = securityService.encodePassword(user.password)
user.save()
UserRole.create user, Role.findByAuthority(Role.PROFESSIONAL)
}
}
render createModelMessages(cmd) as JSON
}
---> Command object
class UserFormCommand {
String email
String name
String password
String confirmPassword
static constraints = {
email(nullable:false, blank:false)
name(nullable:false, blank:false)
password(size: 4..10)
confirmPassword(size: 4..10, validator: { val, obj, errors ->
if(!val.equals(obj.password))
})
}
}
-
Hide
- grails8343.zip
- 21/Nov/11 11:51 AM
- 196 kB
- Jeff Brown
-
- grails8343/.classpath 0.7 kB
- grails8343/.gitignore 0.0 kB
- grails8343/.project 0.5 kB
- grails8343/.../org.codehaus.groovy.eclipse.preferences.prefs 0.1 kB
- grails8343/application.properties 0.2 kB
- grails8343/grails-app/.../BootStrap.groovy 0.1 kB
- grails8343/grails-app/.../BuildConfig.groovy 1 kB
- grails8343/grails-app/conf/Config.groovy 4 kB
- grails8343/grails-app/.../DataSource.groovy 0.8 kB
- grails8343/grails-app/.../UrlMappings.groovy 0.2 kB
- grails8343/grails-app/.../resources.groovy 0.0 kB
- grails8343/.../DemoController.groovy 0.3 kB
- grails8343/.../messages.properties 3 kB
- grails8343/.../messages_da.properties 3 kB
- grails8343/.../messages_de.properties 4 kB
- grails8343/.../messages_es.properties 3 kB
- grails8343/.../messages_fr.properties 2 kB
- grails8343/.../messages_it.properties 2 kB
- grails8343/.../messages_ja.properties 2 kB
- grails8343/.../messages_nl.properties 3 kB
- grails8343/.../messages_pt_BR.properties 3 kB
- grails8343/.../messages_pt_PT.properties 3 kB
- grails8343/.../messages_ru.properties 4 kB
- grails8343/.../messages_th.properties 5 kB
- grails8343/.../messages_zh_CN.properties 2 kB
- grails8343/grails-app/views/error.gsp 2 kB
- grails8343/grails-app/views/index.gsp 4 kB
- grails8343/grails-app/.../layouts/main.gsp 0.8 kB
- grails8343/.../DemoFunctionalTests.groovy 0.4 kB
- grails8343/.../applicationContext.xml 1 kB
-
Hide
- grails8343-137.zip
- 28/Dec/11 7:32 AM
- 215 kB
- Simon Pither
-
- grails8343-137/application.properties 0.2 kB
- grails8343-137/web-app/css/main.css 5 kB
- grails8343-137/web-app/css/errors.css 2 kB
- grails8343-137/web-app/css/mobile.css 1 kB
- grails8343-137/.../apple-touch-icon.png 5 kB
- grails8343-137/web-app/.../grails_logo.png 10 kB
- grails8343-137/web-app/.../information.png 0.8 kB
- grails8343-137/web-app/.../skin/house.png 0.8 kB
- grails8343-137/web-app/.../skin/shadow.jpg 0.3 kB
- grails8343-137/web-app/.../database_save.png 0.7 kB
- grails8343-137/.../database_delete.png 0.6 kB
- grails8343-137/web-app/.../sorted_desc.gif 0.8 kB
- grails8343-137/.../database_table.png 0.7 kB
- grails8343-137/web-app/.../exclamation.png 0.7 kB
- grails8343-137/web-app/.../database_add.png 0.6 kB
- grails8343-137/web-app/.../sorted_asc.gif 0.8 kB
- grails8343-137/web-app/.../database_edit.png 0.7 kB
- grails8343-137/web-app/.../leftnav_top.png 3 kB
- grails8343-137/web-app/.../springsource.png 9 kB
- grails8343-137/web-app/.../spinner.gif 2 kB
- grails8343-137/web-app/.../leftnav_btm.png 4 kB
- grails8343-137/.../apple-touch-icon-retina.png 15 kB
- grails8343-137/.../leftnav_midstretch.png 3 kB
- grails8343-137/web-app/.../favicon.ico 10 kB
- grails8343-137/web-app/.../grails_logo.jpg 8 kB
- grails8343-137/web-app/js/application.js 0.4 kB
- grails8343-137/web-app/.../slider.js 10 kB
- grails8343-137/web-app/.../unittest.js 20 kB
- grails8343-137/web-app/.../scriptaculous.js 3 kB
- grails8343-137/web-app/.../effects.js 38 kB
-
Hide
- grails8343-200.zip
- 28/Dec/11 7:32 AM
- 215 kB
- Simon Pither
-
- grails8343-200/application.properties 0.2 kB
- grails8343-200/web-app/css/main.css 5 kB
- grails8343-200/web-app/css/errors.css 2 kB
- grails8343-200/web-app/css/mobile.css 1 kB
- grails8343-200/.../apple-touch-icon.png 5 kB
- grails8343-200/web-app/.../grails_logo.png 10 kB
- grails8343-200/web-app/.../information.png 0.8 kB
- grails8343-200/web-app/.../skin/house.png 0.8 kB
- grails8343-200/web-app/.../skin/shadow.jpg 0.3 kB
- grails8343-200/web-app/.../database_save.png 0.7 kB
- grails8343-200/.../database_delete.png 0.6 kB
- grails8343-200/web-app/.../sorted_desc.gif 0.8 kB
- grails8343-200/.../database_table.png 0.7 kB
- grails8343-200/web-app/.../exclamation.png 0.7 kB
- grails8343-200/web-app/.../database_add.png 0.6 kB
- grails8343-200/web-app/.../sorted_asc.gif 0.8 kB
- grails8343-200/web-app/.../database_edit.png 0.7 kB
- grails8343-200/web-app/.../leftnav_top.png 3 kB
- grails8343-200/web-app/.../springsource.png 9 kB
- grails8343-200/web-app/.../spinner.gif 2 kB
- grails8343-200/web-app/.../leftnav_btm.png 4 kB
- grails8343-200/.../apple-touch-icon-retina.png 15 kB
- grails8343-200/.../leftnav_midstretch.png 3 kB
- grails8343-200/web-app/.../favicon.ico 10 kB
- grails8343-200/web-app/.../grails_logo.jpg 8 kB
- grails8343-200/web-app/js/application.js 0.4 kB
- grails8343-200/web-app/.../slider.js 10 kB
- grails8343-200/web-app/.../unittest.js 20 kB
- grails8343-200/web-app/.../scriptaculous.js 3 kB
- grails8343-200/web-app/.../effects.js 38 kB
Activity
- All
- Comments
- Work Log
- History
- Activity
- Git Commits
Hi Jeff,
Yes, it does. I've got the same exception after clean.
Caused by: java.lang.NoSuchMethodError: UserFormCommand.validate()Z
Unfortunately, due to some security policy i can't submit the whole project i'm working on... But i think i can prepare an isolated project with the same behavior. Is it ok?
The attached grails8343.zip file contains a project that was originally written with Grails 1.3.7 and then upgrade to Grails 2.0.0.RC1. The app includes a functional test. "grails test-app functional:" passes with 1.3.7 and with 2.0.0.RC1.
If you can isolate a problematic scenario, that would be helpful.
Thanks again.
The attached app includes code which looks like this:
class DemoController {
def create = { UserFormCommand cmd ->
def result = cmd.validate()
render "Result: ${result}"
}
}
class UserFormCommand {
String name
static constraints = {
name size: 4..10
}
}
class DemoFunctionalTests extends functionaltestplugin.FunctionalTestCase { void testCommandObjectValidation() { get('/demo/create?name=ab') assertStatus 200 assertContentContains 'Result: false' get('/demo/create?name=abcde') assertStatus 200 assertContentContains 'Result: true' } }
Osvaldo,
Have you had any luck creating an isolated project which demonstrates this problem?
Thanks again for the help.
Hello,
I would like to ask if the Validateable annotation is mandatory for Command objects that define constraints. Is it true?
I remember it worked without the annotation on 2.0.RC1, but on RC2 I had to add the annotation.
Thanks
The Validateable annotation should not be applied to command objects classes. Are you able to create a sample app which demonstrates the .validate() method not being available on a command object?
Jeff,
I tried to isolate the error and i could not reproduce exactly as it happened in my production project. Actually i've noted this exception is thrown (sometimes) in 2.0.0.RC1, and only when i've passed one more parameter to the validator closure like the following:
String email
String name
String password
String confirmPassword
static constraints = {
email(nullable: false, blank: false)
name(nullable: false, blank: false)
password(size: 4..10, validator: {val, cmd, errors -> <---- Does not works and an exception is thrown
return val != cmd.name
})
confirmPassword(size: 4..10, validator: { val, cmd -> <---- Works correctly in both version
return val == cmd.password
})
}
After my analysis, i'm not sure this is a real bug.
I am currently experiencing this bug on my system. It occurs when the command object is in a different package than the controller. I get the problem if I merely declare the command object as a parameter to the controller, regardless of whether I actually use it. This is something of a showstopper for me. I am using 2.0.0.RC3.
Edit: This is sporadically occuring and not occuring for me. It might have something to do with reloading.
I've found that the problem occurs for me when the command object is in it's own .groovy file (i.e. UserSearchCommand.groovy) that is placed in the "controllers" directory, but not when the command is declared within the controller file itself, after the actual controller class. I'll try to reproduce in a test and upload if I can get it to work.
Jordan,
The original issue was reported against 2.0.RC1. If you can reproduce it with 2.0.0 final release, that would be more useful.
If the problem exists I suspect it may be a reloading issue.
I had a similar problem with the command object. My command object was in a plugin. I was able to work around this problem by creating a command object in the same file as the controller and then extending the command object with the command object in the plugin.
I've attached two example projects, based on the original one but with the command object moved to an inline plugin.
The -137 project is setup for grails 1.3.7 and the functional test passes.
The -200 project is setup for grails 2.0.0 final and the functional test fails.
I think the "command object not working in a plugin" may be a deliberate change in behaviour that didn't make it into the upgrade docs. http://jira.grails.org/browse/GRAILS-7900 and related issues seem to be relevant.
Certainly the -200 example project can be fixed by adding:
import org.codehaus.groovy.grails.validation.Validateable
@Validateable
To the top of the command object file. The same change also continues to work within grails 1.3.7 too.
Simon,
Thanks for attaching the projects. I will take a look and figure out what is going on. It may be that the inline plugin is relevant.
As for @Validateable, command objects should not require the @Validateable annotation. Command objects are supposed to be rigged up as validateable even if they aren't marked with @Validateable.
In Grails 2.0 org.codehaus.groovy.grails.validation.Validateable is deprecated in favor of grails.validation.Validateable. They both behave the same right now but the deprecated one is subject to removal in a future release.
Thanks again for the help.
I think I see what the problem here is. UserFormCommand is not really a command object, at least when it is compiled it isn't. What makes a class a command object is that it must be used as an argument to a controller action. Since UserFormCommand is defined in a plugin and that plugin never uses it as an argument to a controller action, when the plugin is compiled the class isn't recognized as a command object.
We will look at options to deal with this. It may be that we just runtime enhance classes like these. In the meantime, if the class must be defined in a plugin and that plugin doesn't treat the class as a command object, maybe the best thing to do is mark it with @Validateable.
What's the feasibility of turning command objects into full, first-class grails artefacts? I.e. have a /command directory to put them all in. Is something along these lines planned as a future feature? If not, this seems like a good idea for a community plugin.
Jordan,
Would you anticipate that anything special happen to classes defined under the command/ directory aside from them being made validateable?
They would be eligible for automatic data-binding as well. For me, this has been the biggest benefit of command objects. Automatically binding a request parameter named "user.id" to a command object field "user", with all the intermediate type conversion and get() call, catching exceptions, etc, has great utility.
Note that I'm unclear on the internal data binding mechanics and I've been assuming that only domain objects and command objects are subject to data-binding. If this is indeed the case, then I think it makes sense to treat them as first-class artefacts. If this is not the case, then please disregard this request (but then what is the difference between a command object and any random class that's @Validatable?).
If another directory under /grails-app is undesirable, then I would suggest /controllers with the "Command" suffix as the convention for distinguishing command objects. In either case I think they currently occupy a confusing nether region between POJOs and full-fledged Grails artefacts.
This seems to be getting off-topic for this issue. I'll make a separate JIRA feature request.
There isn't anything special done to command objects to make them subject to data-binding. The real difference between a command object and any other class that is marked @Validateable is that command object classes typically don't need the @Validateable. They are made validateable by convention. At present the convention is if the class is used as a parameter to a controller action, we automatically make it validateable.
I have the same problem using Grails 2.0. My command object is also located in its own groovy file.
No, it's not in a plugin. I've tried many workarounds but the only one that worked was moving the command object class in the controller. I didn't want to revert to Grails 1.3.x.
off-topic: I have The Definitive Guide to Grails book opened next to me. Thanks for writing it so clearly - it saved me countless hours - a Grails newb :^)
Sebastien,
If you could attach a sample application which demonstrates the problem as it relates to a command object which is not defined in a plugin, that would be helpful.
Hi,
I'm using Grails 2.1.0-RC2 and I have this problem. If I put mi CommandObject in a .groovy file it doesn't work. When I put the command object code in controller this works fine.
Is it possible that the problem occurred in version 2.1.0-RC2?
Regards
Juan,
Using 2.1.0-RC2 if you create a controller that uses a command object which is defined under src/groovy and is not marked @Validateable, the compiler should issue a warning letting you know that the thing will not be validateable. The docs at http://grails.org/doc/2.1.0.RC2/guide/theWebLayer.html#commandObjects mention this.
If a command object class is not defined in the same source file as a controller which uses the class as a command object and the class is not marked with Validateable, the class will not be made validateable. It is not required that command object classes be validateable.
If your app includes something like this:
package com.demo class DemoController { def index(DemoCommand co) { render "It Worked" } }
package com.demo class DemoCommand { String name }
The compiler should issue a warning like this:
| Compiling 10 source files
| Warning The [index] action accepts a parameter of type [com.demo.DemoCommand] which has not been marked with @Validateable. Data binding will still be applied to this command object but the instance will not be validateable.
def index(DemoCommand co) {
^
Is that what you are seeing?
Ouch!! I was using the 'latest' documentation version (http://grails.org/doc/latest/), and this point to 2.0.4 versión where the command object usage is different.
I see it's necessary mark with Validatable and not register the class. Now, It's working like a charm!
Thank you very much!
Juan,
Apologies for the confusion. The "latest" docs are for the latest released version of the framework, not snapshots and RCs. Once we release 2.1 the "latest" docs will point to that and the 2.0 docs will be available at http://grails.org/doc/2.0.x/ (they already are actually).
I am glad you got it all working.
Does the error persist after doing a "grails clean"?