Bean Validation Messages in JSF 2

JSF 2 introduced support for standard JSR-303 Bean Validation. One of the surprising bits was the default error messages.

Suppose I added an annotation to one of my form beans as follows:

public class Booking {

    @NotEmpty
    private String creditCardName;

}

and then I bind it to a form input field:


<h:messages />

<h:inputText label="Credit Card Name" 
            value="#{booking.creditCardName}"/>
  

The resulting error message I get is: “may not be empty”. Huh? What may not me empty? :)

This makes no sense when shown as a global message at the top of the page. You get a sequence like “may not by empty, may not be null, must be in the future”. This also makes no sense when shown as a field specific message either: “may not be empty” is a partial sentence. I recall being surprised by this initially and that I’d have to come back to it eventually.

So I did and here is what I found out. To start off the above messages are defined by the Bean Validation provider (Hibernate Validator in this case) in a file called ValidationMessages.properties. When the JSF BeanValidator invokes Bean Validation and then formats the messages, it holds two pieces of data — one is the constraint message (e.g. “may not be empty”) and the second is the field label (“Credit Card Name”). To format the message the BeanValidator uses the pattern “{0}”, which practically ignores the field label.

Mind you that I had to find this out by debugging. And it’s what most developers would have to do. It turns out the spec has something to say about this. Here is a quote:

To encourage use of the Bean Validation message facility, the default message format string for the BeanValidator
message key must be a single placeholder, as shown here:

javax.faces.validator.BeanValidator.MESSAGE={0}

Putting the Bean Validation message resolution in full control of producing the displayed message is the recommended approach. However, to allow the developer to align the messages generated by the BeanValidator with existing JSF 1.2 validators, the developer may choose to override this message key in an application resource bundle and reference the component label, which replaces the second numbered placeholder (i.e., {1}).

javax.faces.validator.BeanValidator.MESSAGE={1}: {0}

If I understand correctly, the intent behind all this is to encourage use of Bean Validation facilities to control messages. Seems like a fair idea but one that I don’t get on multiple levels.

  1. How would the Bean Validation provider know what is an appropriate label for a given Java field? This is the domain of JSF and that’s why I have a “label” attribute on my <inputText> above.
  2. The default behavior you get out of the box is one that I can’t imagine anyone would want. So everyone has to do extra work to get JSF and Bean Validation to produce messages based on JSF component labels.
  3. This changes the behavior from JSF 1.2 for an unknown benefit.

Well, maybe there is something in the Bean Validation spec that can address this. I haven’t found this yet but logically it seems to be that labels are defined in JSF components and the JSF integration with Bean Validation should make use of that.

In the mean time to correct this you’ll need to create a resource bundle, overwrite the message pattern the BeanValidator uses, and then register your resource bundle in faces-config.xml.

For example I add ApplicationMessages.properties to my classpath with this content:

javax.faces.validator.BeanValidator.MESSAGE={1} {0}

Then I register it in faces-config.xml as follows:


<?xml version='1.0' encoding='UTF-8'?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="

http://java.sun.com/xml/ns/javaee


http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"

        version="2.0">

	<application>
		<message-bundle>ApplicationMessages</message-bundle>
	</application>
	    
</faces-config>

At last I get: “Credit card name may not be empty”! Simple solution but a long winded path to get to it.

This entry was posted in JSF. Bookmark the permalink.

5 Responses to Bean Validation Messages in JSF 2

  1. Daniel Camargo says:

    You can also define the key:

    javax.faces.validator.BeanValidator.MESSAGE_detail

    In case you need the summary and the detail message displayed.

  2. Matt Handy says:

    Thank you, this works!

  3. Hartwig says:

    Why not annotating:
    @NotEmpty(message=”Credit card is a required field”) ?
    At least for me this works…

  4. Administrator says:

    Hartwig, yes that works but then you have to add the message to every field in addition to the label on the input field.

  5. Julien says:

    @NotEmpty is not part of JSR-303, but is part of Hibernate Validator.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>