Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Playframework IllegalStateException after form validation

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,

like image 994
John Smith Avatar asked Jul 09 '12 01:07

John Smith


2 Answers

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

like image 175
pabloi Avatar answered Oct 22 '22 10:10

pabloi


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...

like image 23
ndeverge Avatar answered Oct 22 '22 11:10

ndeverge