17 May 2011

Observing Bean Validation at JPA Level

A quick followup to yesterdays posting regarding the use of JSF 2.0, JPA 2.0 and Bean Validation.

To verify the validation of the constraints at the JPA level, and not at the JSF front end, I decided to add a simple Servlet which calls the WidgetFacadeLocal directly to create a new Widget entity.

This led to a small, interesting side excursion.

Since the NetBeans project was defined as a Java EE 6 Web Application, when the new Servlet was added, the default option was to not generate a web.xml descriptor to describe the Servlet configuration and mapping, and instead to define the Servlet using the @WebServlet annotation on the Servlet class itself.

@WebServlet(name = "TestValidationServlet", urlPatterns = {"/TestValidationServlet"})
public class TestValidationServlet extends HttpServlet {

Now this won't deploy in this form to WebLogic Server 10.3.4 since it doesn't yet implement the Servlet 3.0 specification and support @WebServlet.  But ... WebLogic Server has provided it's own specific annotation for Servlets since the 10.3 timeframe.


Therefore to have this Servlet deploy and run on WebLogic Server, without introducing a web.xml file, the @WLServlet annotation can simply be added to the Servlet class, looking like this:

@WebServlet(name = "TestValidationServlet", urlPatterns = {"/TestValidationServlet"})
@weblogic.servlet.annotation.WLServlet(name = "TestValidationServlet", mapping = "/TestValidationServlet")
public class TestValidationServlet extends HttpServlet {

At compile time, add a reference to $WL_HOME/modules/com.bea.core.weblogic.web.api_1.4.0.0.jar to make the annotation available and it'll build and package successfully.

With that small excursion done, and the Servlet able to be deployed to WebLogic Server with the addition of the single @WLServlet annotation, the JPA validation can be tested.

This can be simply done again by injecting the stateless session bean WidgetFacadeLocal using an @EJB annotation, then creating a Widget with a known invalid property, and attempting to persist it through the session bean.  Any validation constraints that are violated will be detected and returned in an EJBException that can be checked, and displayed.

@EJB WidgetFacadeLocal widgetFacade;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    try {      
        Widget widget = new Widget();
        widget.setName("My Widget");
    } catch (EJBException ejbex) {
        out.printf("<p>EJBException, caused by: %s</p>", ejbex.getCause().getClass().getName());
        if (ejbex.getCausedByException() instanceof ConstraintViolationException) {
            ConstraintViolationException cve = (ConstraintViolationException) ejbex.getCausedByException();
            out.printf("<p>Constraint Validations:</p>");

            for(ConstraintViolation cv: cve.getConstraintViolations()) {
                out.printf("<li>%s, <b>%S</b>, %s, <span style='color: red;'>%s</span></li>",

Here the Widget has an email address which is not valid, as well as missing the mandatory pricePerUnit property.

Deploying this to the WebLogic Server 10.3.4 domain used previously with JPA 2.0 enabled, and Bean Validation library added to the server classpath, the simple test shows that the Bean Validations are checked.   An exception is returned that contains the set of constraint violations that occurred, which can be displayed to a user.

This demonstrates the use of implicit Bean Validation through using JPA 2.0 running on WebLogic Server 10.3.4.

Again, the key is to firstly ensure that the Server ClassPath is set to include the following libraries to expose and enable JPA 2.0 and have the Bean Validation implementation be visible to the JPA 2.0 provider:
  • $WLS_HOME/modules/com.oracle.jpa2support_1.0.0.0_2-0.jar
  • $WLS_HOME/modules/javax.persistence_1.0.0.0_2-0-0.jar
  • $GF_HOME/glassfish3/glassfish/modules/bean-validator.jar
And secondly, ensure that either the default JPA provider on the domain is set to TopLink, or the provider is specifically set to be org.eclipse.persistence.jpa.PersistenceProvider in persistence.xml within the application.

No comments: