I tried to write a custom form validator for play 2.0.1 using JSR-303 annotation (class-level) and validator implementations.
Unfortunately, when i submit the form and validation fails i get an IllegalStateException that might be a play's bug (but i would like to confirm).
Please find below the relevant code extracts and the problem description (only relevant parts for clarity's sake)
Part of the controller code (receiving the form submit)
public static Result save() {
Form<UserForm> userForm = form(UserForm.class).bindFromRequest();
if (userForm.hasErrors()) {
return badRequest(createForm.render(userForm));
}
UserForm user = userForm.get();
The validator is declared as
public class FieldMatchValidator extends Validator<Object>
implements ConstraintValidator<FieldMatch, Object>
The validation annotation is declared as
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
@play.data.Form.Display(name="constraint.fieldmatch")
public @interface FieldMatch {
String message() default FieldMatchValidator.message;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Submitting the form i get the error
Caused by: java.lang.IllegalStateException: No value
at play.libs.F$None.get(F.java:217) ~[play_2.9.1.jar:2.0.1]
at play.data.Form.get(Form.java:363) ~[play_2.9.1.jar:2.0.1]
at controllers.UsersController.save(UsersController.java:40) ~[classes/:2.0.1]
at Routes$$anonfun$routes$1$$anonfun$apply$25$$anonfun$apply$26.apply(routes_routing.scala:189) ~[classes/:na]
at Routes$$anonfun$routes$1$$anonfun$apply$25$$anonfun$apply$26.apply(routes_routing.scala:189) ~[classes/:na]
at play.core.Router$HandlerInvoker$$anon$4$$anon$1.invocation(Router.scala:1086) ~[play_2.9.1.jar:2.0.1]
The mentioned UsersController's line is the call UserForm user = userForm.get();
Trying to understand where the problem is i found that the offending code is probably in play's Form.java.
The Form bind(Map data, String... allowedFields) contains:
if(result.hasErrors()) {
for(FieldError error: result.getFieldErrors()) {
...
}
return new Form(rootName, backedType, data, errors, None());
}
And the hasErrors() is
public boolean hasErrors() {
return !errors.isEmpty();
}
What happens is that result.hasErrors() returns true (because the validator defined at class level failed), but the built errors list remains empty (result.getFieldErrors() returns an empty list).
As a consequence Form.hasErrors() returns false but Form.get() fails.
Am i missing something or is it actually a bug ?
Thanks and regards,
It's a bug on play. If your form implements validate just make sure the method returns null whenever there are no errors. If you return an empty map then it will fail
I hit the same issue, and since I wasn't able to figure out is it is a Play! bug or a bad use from me, I ended up writing my own Form
class by extending the existing Form
class.
You can find my class here: https://gist.github.com/3074629
Just put this class in a package called patch
, then, in your controller, you'll have to use:
Form<UserForm> userForm = new PatchedForm<UserForm>(UserForm.class).bindFromRequest();
And it should make it ;-)
Now, I have to fill a bug and a pull request to the Play team...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With