mscharhag, Programming and Stuff;

A blog about programming and software development topics, mostly focused on Java technologies including Java EE, Spring and Grails.

Monday, 28 May, 2018

Java EE MVC: Handling form validation

In this post we will have a look on form validation in Java EE MVC.

Java EE MVC integrates with the Java Bean Validation API (JSR 303) which makes adding validation constraints pretty easy.

Validation using the JAX-RS way

Assume we have a small html form that can be used to send contact messages. To represent the form data we create a small ContactMessage bean containing the form fields and validation constraints:

public class ContactMessage {

    @FormParam("message")
    @NotBlank
    @Size(max = 1000)
    private String message;

    // getters / setters
}

In our MVC controller we use the @BeanParam annotation to convert the form data to a ContactMessage object:

@Controller
@Path("/")
public class ContactController {

    @POST
    public String formSubmit(@Valid @BeanParam ContactMessage message) {
        ...
    }
}

(For more details about the @BeanParam annotation, have a look at the blog post Working with bean parameters)

By adding the @Valid annotation to the ContactMessage parameter we enable validation. If a form is submitted and the validation of the ContactMessage object fails, a ConstraintViolationException will be thrown. The controller method will not be called in this case. Instead, the exception can be handled using a generic JAX-RS ExceptionMapper like shown in another post: Global Exception handling in Java EE MVC.

This approach is typically fine for standard JAX-RS REST endpoints. Here we often want to return a generic HTTP 400 (Bad request) status code if invalid data has been passed to the server.

In an MVC environment we can use this behaviour to render a standard error page to the user, whenever invalid data has been passed. However, this is often not flexible enough. Often we want to return a more specific page that shows an error message to the user.

Validation using @MvcBinding and BindingResult

Java EE MVC provides a @MvcBinding annotation that enables an alternative exception handling mechanism. @MvcBinding can be placed on fields and method parameters together with JAX-RS binding annotations (like @FormParam):

public class ContactMessage {

    @MvcBinding
    @FormParam("message")
    @NotBlank
    @Size(max = 1000)
    private String message;

    // getters / setters
}


This tells Java EE MVC to call the controller method instead of the generic exception handler if binding of the annotated field fails. To access binding information, we can inject a BindingResult object into our controller class:

@Controller
@Path("/")
public class ContactController {

    @Inject
    private Models models;

    @Inject
    private BindingResult bindingResult;

    @POST
    public String formSubmit(@Valid @BeanParam ContactMessage message) {
        if (bindingResult.isFailed()) {
            models.put("bindingResult", bindingResult);
            return "/WEB-INF/jsp/contact.jsp";
        }
        return "/WEB-INF/jsp/success.jsp";
    }
}

As the name suggests, we can use the injected BindingResult object to access binding information within a controller method. In this example we simply check if there was a binding problem by calling isFailed(). By adding the bindingResult to the model, we can access it later in the view to show an error message to the user.

A simple JSP view that displays all validation errors below the submit button looks like this:

<form action="${mvc.contextPath}/contact" method="post">
    <label>Message:</label>
    <textarea name="message"></textarea>
    <br/>

    <input type="submit"/>

    <c:if test="${bindingResult.isFailed()}">
        <p>Form validation failed. Reasons:</p>
        <ul>
            <c:forEach items="${bindingResult.allValidationErrors}" var="validationError">
                <li>
                    <c:out value="${validationError.paramName}: ${validationError.message}"/>
                </li>
            </c:forEach>
        </ul>
    </c:if>
</form>

Conclusion

Form validation is pretty easy with Java EE MVC. Validation constraints can be added to beans using JSR 303 Bean validation annotations. @MvcBinding allows us to handle validation errors within controller methods instead of using generic ExceptionMappers. BindingResult gives us access to validation information.

As always you can find the example code on GitHub.

Leave a reply