© Bauke Scholtz, Arjan Tijms 2018

Bauke Scholtz and Arjan Tijms, The Definitive Guide to JSF in Java EE 8, https://doi.org/10.1007/978-1-4842-3387-0_5

5. Conversion and Validation

Bauke Scholtz and Arjan Tijms2

(1)Willemstad, Curaçao

(2)Amsterdam, Noord-Holland, The Netherlands

At its core, JSF (JavaServer Faces) as an HTML form-based MVC (Model-View-Controller) framework basically needs to convert between Java objects (entities, beans, value objects, data transfer objects, and what not) and character sequences (strings) all the time. The HTTP request is basically broken down into plain vanilla strings representing headers and parameters, not as Java objects. The HTTP response is basically written as one big sequence of characters representing HTML or XML, not as some sort of serialized form of a Java object. However, the average Java model behind a JSF page doesn’t necessarily contain String properties everywhere. That would defeat the strong typed nature of Java. This is where Converters come into the picture: converting between objects in model and strings in view.

Before updating the model values with freshly submitted and, if necessary, converted values, you would of course like to validate whether they conform to the business rules of the web application and, if necessary, present end users an informative error message so that they can fix any errors themselves. Usually, the business rules are already very well defined in the data store, such as a relational database management system. A decently designed database table already has strict constraints on the data type, maximum size, nullability, and uniqueness. You as a front-end developer should make absolutely sure that the submitted and converted values can be inserted in the database without errors.

If, for example, the e-mail address column is constrained as a unique and non-nullable column with a maximum size of 254 characters, then you should make sure that the submitted value is validated as such before inserting it in the database. Otherwise, the database insert would throw some exception which is generally cumbersome to break down into detailed information in order to tell the end user about the exact mistake. This is where Validators come into the picture: validating submitted (and converted) values before updating the model.

Standard Converters

JSF has, from the beginning, provided a bunch of standard converters out the box. Most of them even do their job fully transparently based on the Java type of the model property. They are all available in the javax.faces.convert package1 and they all implement the Converter<T> interface . Table 5-1 provides an overview of them.

Table 5-1 Standard Converters Provided by JSF

Converter class

Converter ID

Converter tag

Value type

Since

BigDecimalConverter

javax.faces.BigDecimal

n/a

java.math.BigDecimal

1.0

BigIntegerConverter

javax.faces.BigInteger

n/a

java.math.BigInteger

1.0

BooleanConverter

javax.faces.Boolean

n/a

boolean/java.lang.Boolean

1.0

ByteConverter

javax.faces.Byte

n/a

byte/java.lang.Byte

1.0

CharacterConverter

javax.faces.Character

n/a

char/java.lang.Character

1.0

DateTimeConverter

javax.faces.DateTime

<f:convertDateTime>

java.util.Date

java.time.LocalDate

java.time.LocalTime

java.time.OffsetTime

java.time.LocalDateTime

java.time.OffsetDateTime

java.time.ZonedDateTime

1.0

2.3

2.3

2.3

2.3

2.3

2.3

DoubleConverter

javax.faces.Double

n/a

double/java.lang.Double

1.0

EnumConverter

javax.faces.Enum

n/a

enum/java.lang.Enum

1.0

FloatConverter

javax.faces.Float

n/a

float/java.lang.Float

1.0

IntegerConverter

javax.faces.Integer

n/a

int/java.lang.Integer

1.0

LongConverter

javax.faces.Long

n/a

long/java.lang.Long

1.0

NumberConverter

javax.faces.Number

<f:convertNumber>

java.lang.Number

1.0

ShortConverter

javax.faces.Short

n/a

short/java.lang.Short

1.0

The “Converter ID” column basically specifies the converter identifier as you could specify in the converter attribute of any ValueHolder component, or the converterId attribute of any nested <f:converter> tag in order to activate the specific converter. All UIOutput and UIInput components implement the ValueHolder interface. The converters which say “n/a” in the “Converter tag” column are implicit converters. In other words, you can just bind any bean property of type BigDecimal, BigInteger, boolean/Boolean, byte/Byte, char/Character, double/Double, enum/Enum, float/Float, int/Integer, long/Long, and short/Short to the value attribute of any ValueHolder component and have JSF to automatically convert it without any additional configuration. Only <f:convertDateTime> and <f:convertNumber> require explicit registration, because the desired conversion algorithm isn’t necessarily obvious from the model value alone.

In all ValueHolder components , the converter will be invoked during the render response phase (sixth phase), converting the non-String-based model value to a String suitable for embedding in HTML. And in EditableValueHolder components, the converter will also be invoked during the process validations phase (third phase), converting the submitted String request parameter to the non-String-based model value. The EditableValueHolder interface extends the ValueHolder interface and is implemented by all UIInput components.

However, this implicit conversion doesn’t work on bean properties where those types are parameterized. Imagine that you have a List<Integer> in the model and you’d like to be able to edit it as follows:

<ui:repeat value="#{bean.integers}" varStatus="loop">
    <h:inputText value="#{bean.integers[loop.index]}" />
</ui:repeat>

Then, after submitting, you would end up with unconverted String values in the list and get baffled by class cast exceptions when attempting to iterate over the list. The reason is that the EL (Expression Language) API (application programming interface), which is responsible for processing those #{...} things that are, behind the scenes , represented by javax.el.ValueExpression instances, is in its current version not capable of detecting the parameterized type of a generic collection and just returns Object.class on ValueExpression#getType(). JSF can’t do much about that limitation of EL. All you can do is explicitly specify the desired converter on the input component.

<ui:repeat value="#{bean.integers}" varStatus="loop">
    <h:inputText value="#{bean.integers[loop.index]}"
        converter="javax.faces.Integer">
    </h:inputText>
</ui:repeat>

An alternative is to replace the List<Integer> by Integer[] or even int[]. EL will then be able to recognize the value expression as an integer type and hence JSF will be able to locate the desired converter for it. However, plain arrays instead of collections in the model are a “no-no” these days.

Coming back to the explicit standard converters <f:convertNumber> and <f:convertDateTime>, those can also be nested in any ValueHolder component. The difference between <f:convertNumber> and the implicit number-based converters is that the tags allow more fine-grained setting of conversion options, such as the number type or pattern, the amount of integer and/or fraction digits, whether grouping is used, and the locale.

<f:convertNumber>

<f:convertNumber> 2 uses under the hood java.text.NumberFormat.3 The type attribute specifies which instance will be obtained and defaults to number. Other allowable values are currency and percent. In other words, the following tags ,

<f:convertNumber type="number" />
<f:convertNumber type="currency" />
<f:convertNumber type="percent" />

will under the hood obtain the NumberFormat instance as follows:

NumberFormat numberFormat = NumberFormat.getNumberInstance(locale);
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale);
NumberFormat percentFormat = NumberFormat.getPercentInstance(locale);

where the locale argument can be specified by the locale attribute of the <f:convertNumber> tag and defaults to UIViewRoot#getLocale() which in turn can be specified by the locale attribute of <f:view>. In other words, those instances will automatically apply the standard number format pattern based on the number type and the specified locale. The following example,

<f:view locale="pt_BR">
    ...
    <h:outputText value="#{product.price}">
        <f:convertNumber type="currency" locale="en_US" />
    </h:outputText>
</f:view>

will not format the price (a BigDecimal property) as R$ 12,34 (Brazilian real), but instead as $12.34 (US dollar). Note that the locale attribute of the <f:convertNumber> tag does not necessarily need to be specified as supported locale in faces-config.xml. Also noted should be that the value attribute doesn’t necessarily need to refer a BigDecimal; any other java.lang.Number type is also supported, but for prices we’d of course like to store the value in a BigDecimal instead of, for example, a Double or Float to avoid arithmetic errors due to the floating nature of floating point numbers.4

In case you need to change the standard number format pattern for some reason—for example, because you’re working on a banking application which stores financial data with five fractions—and you’d like to present the full value in some back-end admin screen so that humans can if necessary verify them, then you can use the pattern attribute of the <f:convertNumber> tag to override the standard number format pattern conform the rules of java.text.DecimalFormat.5

<f:convertNumber pattern="¤ #,##0.00000" locale="pt_BR" />

Note that when the pattern attribute is specified, the type attribute is ignored. The “currency sign” pattern character “¤” specifies where the actual currency symbol must be inserted. The actual currency symbol depends on the specified locale. The “comma” pattern character “,” specifies when the grouping separator must be inserted, which is relative to the decimal separator or the end of the value. The actual inserted grouping separator symbol is coincidentally also a comma in US dollar format but is a period in Brazilian real format. The “period” pattern character “.” specifies the location of the decimal separator. The actual inserted decimal separator symbol is coincidentally also a period in US dollar format but is a comma in Brazilian real format. The “optional digit” pattern character “#” is in this pattern merely used to indicate when the grouping separator symbol should be inserted and won’t show anything when the actual digit is absent. The “required digit” pattern character “0” specifies the minimum format which will show zero when the actual digit is absent. Following is an exercise code which should give insight into how <f:convertNumber> works under the hood:

Locale locale = new Locale("pt", "BR");
DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale);


System.out.println("Currency symbol: " + symbols.getCurrencySymbol());
System.out.println("Grouping symbol: " + symbols.getGroupingSeparator());
System.out.println("Decimal symbol: " + symbols.getDecimalSeparator());


DecimalFormat formatter = new DecimalFormat("¤ #,##0.00000", symbols);

System.out.println(formatter.format(new BigDecimal("12.34")));
System.out.println(formatter.format(new BigDecimal(".1234")));
System.out.println(formatter.format(new BigDecimal("1234")));
System.out.println(formatter.format(new BigDecimal("1234567.1234567")));

The output should look as follows:

Currency symbol: R$
Grouping symbol: .
Decimal symbol:,
R$ 12,34000
R$ 0,12340
R$ 1.234,00000
R$ 1.234.567,12346

<f:convertNumber> will also render exactly those values. Apart from the pattern attribute, you can also fine-grain the type attribute with additional attributes such as currencySymbol, integerOnly, groupingUsed, minIntegerDigits, maxIntegerDigits, minFractionDigits, and maxFractionDigits. You can basically achieve the same formatting pattern “¤ #,##0.00000” as follows:

<f:convertNumber type="currency" locale="pt_BR"
    minFractionDigits="5" maxFractionDigits="5" />

This is actually more readable and more convenient in case you have a hard time getting out the currency sign placeholder from your keyboard. The pattern attribute is rarely more useful than fine-graining the type attribute with additional attributes.

In case you’re using <f:convertNumber> in a UIInput component and thus require the end user to enter the value, you should keep in mind that currency and percent types explicitly require the end user to enter the currency or percent symbol as well. For the currency input , you can easily disable this by specifying an empty string as a currency symbol so that you can put it outside the input component.

<span class="currency">
    <span class="symbol">$</span>
    <h:inputText ...>
        <f:convertNumber type="currency" currencySymbol="" />
    </h:inputText>
</span>

For the percent type this is, unfortunately, not possible.

<f:convertDateTime>

<f:convertDateTime> 6 uses under the hood java.text.DateFormat,7 and, since JSF 2.3, also java.time.formatter.DateTimeFormatter.8 In other words, you can use basically any kind of date for this. Also, this tag has a type attribute which must actually correspond to the actual type of the model value. Historically, it was not possible to programmatically detect the desired type based on a java.util.Date instance. This has changed since the new java.time API which offers distinct classes for each date time type. However, in order to be able to reuse the existing <f:convertDateTime> API for the new java.time API, new types had to be added. Table 5-2 provides an overview.

Table 5-2 <f:convertDateTime type> Supported Values

Tag attribute

Value type

Actual formatter

Since

date (default)

java.util.Date (with zero time)

DateFormat#getDateInstance()

1.0

time

java.util.Date (with zero date)

DateFormat#getTimeInstance()

1.0

both

java.util.Date

DateFormat#getDateTimeInstance()

1.0

localDate

java.time.LocalDate

DateTimeFormatter#ofLocalizedDate()

2.3

localTime

java.time.LocalTime

DateTimeFormatter#ofLocalizedTime()

2.3

localDateTime

java.time.LocalDateTime

DateTimeFormatter#ofLocalizedDateTime()

2.3

offsetTime

java.time.OffsetTime

DateTimeFormatter#ISO_OFFSET_TIME

2.3

offsetDateTime

java.time.OffsetDateTime

DateTimeFormatter#ISO_OFFSET_DATE_TIME

2.3

zonedDateTime

java.time.ZonedDateTime

DateTimeFormatter#ISO_ZONED_DATE_TIME

2.3

Along with the type attribute, you should preferably also specify the pattern attribute, particularly when requesting the end user to enter a java.util.Date or java.time.LocalXxx value via a UIInput component, because the actual pattern may vary in a not so self-documenting way across various locales. java.time.OffSetXxx and ZonedDateTime don’t have that problem because they default to the universal ISO 8601 format .9

The pattern attribute of <f:convertDateTime> follows, for java.util.Date, the same rules as specified in the java.text.SimpleDateFormat Javadoc,10 and for the java.time API, the same rules as specified in java.time.format.DateTimeFormatter Javadoc.11 They are for the most part the same, but the java.time format supports more patterns. For both APIs, the “day of month” pattern character is “d”, the “month of year” pattern character is “M”, the “year” pattern character is “y”, the “24h hour” pattern character is “H”, the “minute” pattern is “m”, and the “second” pattern is “s”. The ISO 8601 date format is “yyyy-MM-dd” and the ISO 8601 time format is “HH:mm:ss”. The offset and zoned times require an additional offset after the time part, which is represented by the ISO 8601 time zone pattern character “X”. Examples of valid values are “+01:00” for CET (Central European Time), “-03:00” for BRT (Brasilia Time), and “+5:30” for IST (Indian Standard Time). As before, the offset and zoned date and time need to be separated by the “T” character instead of a space. Following is an overview of all possible <f:convertDateTime> types whereby the localized ones have an explicitly specified pattern:

<h:form id="form">
    <h:inputText id="date" value="#{bean.date}">
        <f:convertDateTime type="date" pattern="yyyy-MM-dd" />
    </h:inputText>
    <h:inputText id="time" value="#{bean.time}">
        <f:convertDateTime type="time" pattern="HH:mm:ss" />
    </h:inputText>
    <h:inputText id="both" value="#{bean.both}">
        <f:convertDateTime type="both" pattern="yyyy-MM-dd HH:mm:ss" />
    </h:inputText>
    <h:inputText id="localDate" value="#{bean.localDate}">
        <f:convertDateTime type="localDate" pattern="yyyy-MM-dd" />
    </h:inputText>
    <h:inputText id="localTime" value="#{bean.localTime}">
        <f:convertDateTime type="localTime" pattern="HH:mm:ss" />
    </h:inputText>
    <h:inputText id="localDateTime" value="#{bean.localDateTime}">
        <f:convertDateTime type="localDateTime"
            pattern="yyyy-MM-dd HH:mm:ss">
        </f:convertDateTime>
    </h:inputText>
    <h:inputText id="offsetTime" value="#{bean.offsetTime}">
        <f:convertDateTime type="offsetTime" />
    </h:inputText>
    <h:inputText id="offsetDateTime" value="#{bean.offsetDateTime}">
        <f:convertDateTime type="offsetDateTime" />
    </h:inputText>
    <h:inputText id="zonedDateTime" value="#{bean.zonedDateTime}">
        <f:convertDateTime type="zonedDateTime" />
    </h:inputText>
    <h:commandButton value="submit" action="#{bean.submit}" />
    <h:messages showSummary="false" showDetail="true"/>
</h:form>

Note that <h:messages> is here reconfigured to show the detail instead of just the summary, because the detail message of a date time conversion error includes in standard JSF an example value which is more useful for the end user in order to understand the required format. Following is what the associated backing bean looks like:

@Named @RequestScoped
public class Bean {


    private Date date;
    private Date time;
    private Date both;
    private LocalDate localDate;
    private LocalTime localTime;
    private LocalDateTime localDateTime;
    private OffsetTime offsetTime;
    private OffsetDateTime offsetDateTime;
    private ZonedDateTime zonedDateTime;


    public void submit() {
        System.out.println("date: " + date);
        System.out.println("time: " + time);
        System.out.println("both: " + both);
        System.out.println("localDate: " + localDate);
        System.out.println("localTime: " + localTime);
        System.out.println("localDateTime: " + localDateTime);
        System.out.println("offsetTime: " + offsetTime);
        System.out.println("offsetDateTime: " + offsetDateTime);
        System.out.println("zonedDateTime: " + zonedDateTime);
    }


    // Add/generate getters and setters.
}

Now that HTML5 has been out for some time and more and more browsers support the new HTML5 date and time inputs ,12 you’d better activate it by default, because it comes with a very useful built-in date picker. The web browser may show the date pattern in the date picker in a localized format, but it will always submit the value in ISO 8601 format. This is thus very useful. The HTML5 date and time inputs can be activated by setting the type attribute of the input text field to “date”,13time”,14 or “datetime-local15 (and thus not “datetime” because it has been dropped). With the JSF <h:inputText>, you’d need to set it as a pass-through attribute . Following are some examples:

<h:form id="form">
    <h:inputText id="localDate" a:type="date" value="#{bean.localDate}">
        <f:convertDateTime type="localDate" pattern="yyyy-MM-dd" />
    </h:inputText>
    <h:inputText id="localTime" a:type="time" value="#{bean.localTime}">
        <f:convertDateTime type="localTime" pattern="HH:mm" />
    </h:inputText>
    <h:inputText id="localDateTime" a:type="datetime-local"
        value="#{bean.localDateTime}">
        <f:convertDateTime type="localDateTime"
            pattern="yyyy-MM-dd'T'HH:mm">
        </f:convertDateTime>
    </h:inputText>
    <h:commandButton value="submit" action="#{bean.submit}" />
    <h:messages showSummary="false" showDetail="true"/>
</h:form>

Following is how they’re rendered in Chrome browser (with newlines added):

A454457_1_En_5_Figa_HTML.jpg

Standard Validators

When the submitted value is successfully converted during the process validations phase (third phase), then JSF will immediately advance to perform validation on the converted value. JSF already provides a handful of standard validators out of the box. They are all available in the javax.faces.validator package16 and they all implement the Validator<T> interface. Table 5-3 provides an overview of them.

Table 5-3 Standard Validators Provided by JSF

Validator class

Validator ID

Validator tag

Value type

Since

LongRangeValidator

javax.faces.LongRange

<f:validateLongRange>

java.lang.Number

1.0

DoubleRangeValidator

javax.faces.DoubleRange

<f:validateDoubleRange>

java.lang.Number

1.0

LengthValidator

javax.faces.Length

<f:validateLength>

java.lang.Object

1.0

RegexValidator

javax.faces.RegularExpression

<f:validateRegex>

java.lang.String

2.0

RequiredValidator

javax.faces.Required

<f:validateRequired>

java.lang.Object

2.0

BeanValidator

javax.faces.Bean

<f:validateBean>

java.lang.Object

2.0

n/a

n/a

<f:validateWholeBean>

java.lang.Object

2.3

The “Validator ID” column basically specifies the validator identifier as you could specify in the validator attribute of any EditableValueHolder component, or the validatorId attribute of any nested <f:validator> tag in order to activate the specific validator. Contrary to the converter, a single EditableValueHolder component can have multiple validators attached. They will all be executed regardless of each other’s outcome.

<f:validateLongRange>/<f:validateDoubleRange>

These validators allow you to specify a minimum and/or maximum allowed number value for an input component tied to a java.lang.Number-based property. Those can be specified with the minimum and maximum attributes .

<h:inputText value="#{bean.quantity}">
    <f:validateLongRange minimum="1" maximum="10" />
</h:inputText>

This is, via pass-through attributes, also combinable with the HTML5 input types “number” (spinner) and “range” (slider), which in turn require min, max, and optionally step as pass-through attributes. In this example, #{bean.quantity} is just an Integer and #{bean.volume} is a BigDecimal.

<h:inputText value="#{bean.quantity}"
    a:type="number" a:min="1" a:max="10">
    <f:validateLongRange minimum="1" maximum="10" />
</h:inputText>
<h:inputText value="#{bean.volume}"
    a:type="range" a:min="1" a:max="10" a:step="0.1">
    <f:validateLongRange minimum="1" maximum="10" />
</h:inputText>

Do note that you can just use <f:validateLongRange> on a BigDecimal property. It doesn’t care about the actual java.lang.Number type of the property being a Long or not, but only the specified minimum and maximum attributes being a Long. In case you want to specify a fractional-based number as minimum and/or maximum , then use <f:validateDoubleRange> instead.

<h:inputText value="#{bean.volume}"
    a:type="range" a:min="0.1" a:max="10.0" a:step="0.1">
    <f:validateDoubleRange minimum="0.1" maximum="10.0" />
</h:inputText>

<f:validateLength>/<f:validateRegex>

These validators are primarily designed for java.lang.String-based properties. <f:validateLength> will first convert the submitted value to string by calling Object#toString() on it and then validate the String#length() result based on the specified minimum and/or maximum attributes. <f:validateRegex> will cast the submitted value to String and then check if String#matches() returns true for the specified pattern attribute. In other words, it doesn’t accept any other property type than java.lang.String. Imagine that you want to validate a value to be always three digits; thus there are three possible ways:

<h:inputText value="#{bean.someStringOrInteger}" maxlength="3">
    <f:validateLength minimum="3" maximum="3" />
</h:inputText>


<h:inputText value="#{bean.someString}" maxlength="3">
    <f:validateRegex pattern="[0-9]{3}" />
</h:inputText>


<h:inputText value="#{bean.someInteger}" maxlength="3">
    <f:validateLongRange minimum="100" maximum="999" />
</h:inputText>

The maxlength="3" attribute is just there so that the end user can’t enter more than three characters on the client side anyway. Storing numbers as strings is plain nonsense, so the second way is scratched. That leaves us with the first or third way. Technically it does not really matter which one you pick. The first way is arguably more self-documenting because you actually want to validate the length, not the range.

Coming back to <f:validateRegex>, the pattern attribute follows exactly the same regular expression rules as specified in java.util.regex.Pattern.17 However, there’s one potential caveat: the necessary amount of escape backslashes depends on the currently used EL implementation. In Oracle’s EL implementation (com.sun.el.*), you need two backslashes, exactly as in a regular Java String, but in Apache’s EL implementation (org.apache.el.*), you must use one backslash, otherwise it will error out or it won’t match as you’d expect. As of now, Payara, WildFly, Liberty, and WebLogic use Oracle’s EL implementation, and TomEE and Tomcat use Apache’s EL implementation. In other words, the following example will work on servers using Oracle EL but won’t work on servers using Apache EL.

<h:inputText value="#{bean.someString}" maxlength="3">
    <f:validateRegex pattern="\d{3}" />
</h:inputText>

When using Apache EL, you need pattern="d{3}" instead. On the other hand, the regular expression pattern d actually means “any digit” and thus matches not only the Latin digits but also the Hebrew, Cyrillic, Arabic, Chinese, etc. If that was not your intent, you’d better use the [0-9] pattern.

<f:validateRequired>

This is a slightly odd beast. That is, all UIInput components already have a required attribute offering exactly the desired functionality. Why would you then use a whole <f:validateRequired> tag instead? It was added in JSF 2.0 specifically for “Composite Components” (more on this later, in Chapter 7). More to the point, in some composite component compositions the template client is given the opportunity to attach converters and validators to a specific EditableValueHolder interface exposed by the composite component, which in turn references one or more UIInput components enclosed in the composite component implementation. Following is an example of such a composite component:

<cc:interface>
    ...
    <cc:editableValueHolder
        name="inputs" targets="input1 input3">
    </cc:editableValueHolder>
</cc:interface>
<cc:implementation>
    ...
    <h:inputText id="input1" ... />
    <h:inputText id="input2" ... />
    <h:inputText id="input3" ... />
    ...
</cc:implementation>

And following is an example of the template client:

<my:compositeComponent ...>
    <f:validateRequired for="inputs" />
</my:compositeComponent>

As you might have guessed, the for attribute must exactly match the name attribute of exposed <cc:editableValueHolder> and this validator will basically target the enclosed input components identified by input1 and input3 (and thus not input2) and thus effectively make them required="true". This for attribute is, by the way, also present on all other converter and validator tags .

<f:validateBean>/<f:validateWholeBean>

When used, these tags have a required dependency on the Bean Validation API (application programming interface), previously more commonly known as “JSR 303.” Like JSF, Bean Validation is part of the Java EE API, already included in any Java EE application server. In Tomcat and other servlet containers, you’d need to install it separately. In Java code, Bean Validation is represented by annotations and interfaces of the javax.validation.* package, such as @NotNull, @Size, @Pattern, ConstraintValidator, etc. Currently the most popular implementation is Hibernate Validator.18

JSF automatically detects the presence of Bean Validation and will in such a case transparently process all Bean Validation constraints during the end of the process validations phase (third phase), regardless of the outcome of JSF’s own validators. If desired, this can be disabled application-wide with the following context parameter in web.xml :

<context-param>
    <param-name>
        javax.faces.validator.DISABLE_DEFAULT_BEAN_VALIDATOR
    </param-name>
    <param-value>true</param-value>
</context-param>

Or, if this is a little too rough, you can fine-grain it with help of the <f:validateBean> tag wrapping a group of UIInput components, or nested in them. When the disabled attribute of the <f:validateBean> tag is set to true, then any Bean Validation will be disabled on the target UIInput components. The following code will disable any Bean Validation only on the parent UIInput component.

<h:inputText ...>
    <f:validateBean disabled="true" />
</h:inputText>

And the following code will disable any Bean Validation only on UIInput components identified by input3, input4, and input5:

<h:inputText id="input1" ... />
<h:inputText id="input2" ... />
<f:validateBean disabled="true">
    <h:inputText id="input3" ... />
    <h:inputText id="input4" ... />
    <h:inputText id="input5" ... />
<f:validateBean>

It is important to keep in mind is that this will only disable JSF-managed Bean Validation and thus not, for example, JPA-managed Bean Validation . So, if you happen to use JPA (Java Persistence API) to persist your entities which are filled out by JSF components with Bean Validation disabled, then JPA would still perform Bean Validation on its behalf, fully independently from JSF. In case you want to disable Bean Validation on the JPA side as well, you need to set the property javax.persistence.validation.mode to NONE in persistence.xml (see also the javax.persistence.ValidationMode Javadoc).19

<property name="javax.persistence.validation.mode">NONE</property>

With the validationGroups attribute of the <f:validateBean> tag you can if necessary declare one or more validation groups. In such a case, only the Bean Validation constraints which are registered on the same group will be processed. Imagine the following model:

@NotNull
private String value1;


@NotNull(groups=NotNull.class)
private String value2;


@NotNull(groups={NotNull.class, Default.class})
private String value3;

Note that the groups attribute of any Bean Validation constraint must reference an interface, but it may be any one you want. For simplicity, in the above example we’re just reusing the javax.validation.constraints.NotNull interface as a group identifier. The common practice is, however, to create your own marker interface for the desired group.

Also not unimportant is that the @NotNull would only work when you’ve configured JSF to interpret empty string submitted values as null; otherwise it would pollute the model with empty strings instead of nulls and cause the @NotNull not to be able to do its job because an empty string is not null. As a reminder, the web.xml context parameter of interest is as follows:

<context-param>
    <param-name>
        javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
    </param-name>
    <param-value>true</param-value>
</context-param>

Now, when submitting an empty form while having those model properties referenced in the following input components, without any <f:validateBean> on them:

<h:inputText value="#{bean.value1}" />
<h:inputText value="#{bean.value2}" />
<h:inputText value="#{bean.value3}" />

you will receive a validation error on Bean Validation constraints belonging to the javax.validation.groups.Default group, which are thus the groupless value1 and the explicitly grouped value3. The value2 won’t be Bean-Validated as it doesn’t have the default group explicitly declared.

And, when submitting an empty form while having <f:validateBean> with validationGroups set to NotNull.class :

<f:validateBean validationGroups="javax.validation.constraints.NotNull">
    <h:inputText value="#{bean.value1}" />
    <h:inputText value="#{bean.value2}" />
    <h:inputText value="#{bean.value3}" />
</f:validateBean>

you will receive a validation error on Bean Validation constraints belonging to the javax.validation.constraints.NotNull group, which are thus the value2 and value3, which explicitly have this group declared. The groupless value1 won’t be Bean-Validated as it only implies the default group.

Finally, when submitting an empty form while having a <f:validateBean> with both groups specified in validationGroups attribute as a comma separated string :

<f:validateBean validationGroups="javax.validation.groups.Default,
                                  javax.validation.constraints.NotNull">
    <h:inputText value="#{bean.value1}" />
    <h:inputText value="#{bean.value2}" />
    <h:inputText value="#{bean.value3}" />
</f:validateBean>

you will receive a validation error on all inputs, because they all match at least one of the specified groups. In real-world applications, however, this grouping feature has very little use. It’s only really useful when the grouped fields can be validated at the same time by the same validator. With Bean Validation, the only way to achieve that is to put a custom Constraint annotation on the bean class itself, get an instance of that bean with the values populated, and then pass it to the custom ConstraintValidator associated with the custom Constraint annotation. Imagine a “period” entity having a “start date” property which should always be before the “end date” property. It would look something like the following:

@PeriodConstraint
public class Period implements Serializable {


    @NotNull
    private LocalDate startDate;


    @NotNull
    private LocalDate endDate;


    // Add/generate getters and setters.
}

With the following custom constraint annotation:

@Constraint(validatedBy=PeriodValidator.class)
@Target(TYPE)
@Retention(RUNTIME)
public @interface PeriodConstraint {
    String message() default "Start date must be before end date";
    Class<?>[] groups() default {};
    Class<?>[] payload() default {};
}

And the following custom constraint validator:

public class PeriodValidator
    implements ConstraintValidator<PeriodConstraint, Period>
{
    @Override
    public boolean isValid
        (Period period, ConstraintValidatorContext context)
    {
        return period.getStartDate().isBefore(period.getEndDate());
    }
}

You see, Bean Validation expects that the model values are present when performing the validation. In the JSF perspective, this means that the model values must be updated before processing the validations. However, this doesn’t fit into the JSF life cycle wherein the model values are only updated after the validations are successfully processed. Essentially, JSF would need to clone the bean instance, populate it with the desired model values, invoke Bean Validation on it, collect any validation errors, and then discard the cloned bean instance.

This is exactly what the <f:validateWholeBean> tag, introduced with JSF 2.3, is doing under the hood. Following is an example form wherein this code is being used:

<h:form>
    <h:inputText a:type="date" value="#{booking.period.startDate}">
        <f:convertDateTime type="localDate" pattern="yyyy-MM-dd" />
    </h:inputText>
    <h:inputText a:type="date" value="#{booking.period.endDate}">
        <f:convertDateTime type="localDate" pattern="yyyy-MM-dd" />
    </h:inputText>
    <h:commandButton value="Submit" />
    <h:messages />
    <f:validateWholeBean value="#{booking.period}" />
</h:form>

With this backing bean:

@Named @ViewScoped
public class Booking implements Serializable {


    private Period period = new Period();

    // Add/generate getter.
}

Do note that <f:validateWholeBean> is explicitly placed as the last child of the parent <h:form>, which ensures that the validation is performed as the last thing after all individual input components in the same form. This is as per the specification; the JSF implementation may throw a runtime exception when the tag is misplaced.

Immediate Attribute

The EditableValueHolder, ActionSource, and AjaxBehavior interfaces also specify an immediate property which basically maps to the immediate attribute of all UIInput and UICommand components and the <f:ajax> tag. When set to true on an EditableValueHolder component, then anything that normally takes place during the process validations phase (third phase) as well as the update model values phase (fourth phase) will be performed during the apply request values phase (second phase). When conversion or validation fails on them, then the life cycle will also skip the process validations phase (third phase). When set to true on an ActionSource component or AjaxBehavior tag, then anything that normally takes place during the invoke application phase (fifth phase) will be performed during the apply request values phase (second phase) and then only if conversion and validation haven’t failed.

Historically, this attribute was mainly used to be able to perform an “inner” action on the form, usually to load a child input component depending on the submitted value of the parent input component, without being blocked by conversion or validation errors coming from other input components in the same form. A common use case was populating a child drop-down on the change of a parent drop-down.

<h:selectOneMenu value="#{bean.country}" required="true" immediate="true"
    onchange="submit()" valueChangeListener="#{bean.loadCities}">
    <f:selectItems value="#{bean.countries}" />
</h:selectOneMenu>
<h:selectOneMenu value="#{bean.city}" required="true">
    <f:selectItems value="#{bean.cities}" />
</h:selectOneMenu>

This approach obviously predates the Web 2.0 era wherein you’d just use Ajax for this. Understand that the immediate attribute has essentially become useless for this purpose since the introduction of <f:ajax> in JSF 2.0. Exactly the same use case can be achieved in a much cleaner way as follows:

<h:selectOneMenu value="#{bean.country}" required="true">
    <f:selectItems value="#{bean.countries}" />
    <f:ajax listener="#{bean.loadCities}" render="city" />
</h:selectOneMenu>
<h:selectOneMenu id="city" value="#{bean.city}" required="true">
    <f:selectItems value="#{bean.cities}" />
</h:selectOneMenu>

As you learned in Chapter 4, the execute attribute of <f:ajax> already defaults to @this, so it’s just omitted. This also means that all other EditableValueHolder components in the same form won’t be processed and thus won’t cause #{bean.loadCities} ever to be blocked by conversion or validation errors coming from other inputs.

These days, with Ajax magic and all, the immediate attribute has thus lost its main use case. JSF could do as well without it. Due to its historic use case, many starters may mistake its primary purpose to be “skip all validation.” This is, however, not true. For that, you’d need to fine-tune the execute attribute of <f:ajax> so that it only covers the input components that really need to be validated. In case you want to actually “skip all validation” while submitting the entire form , you’d best use Bean Validation constraints instead (the @NotNull and friends) and simply have <f:validateBean disabled="true"> wrapping the entire form.

Custom Converters

From the beginning JSF has supported custom converters. The main use case is to be able to convert a non-standard model value, such as a persistence entity specific to the web application. The less common use case is to extend an existing standard converter and set some commonly used defaults in its constructor so that you can get away with less code in order to declare the desired standard converter configuration in the view.

Imagine that you want to be able to create master-detail pages on your persistence entities wherein you’d like to pass the ID of the entity around as a request parameter from the master page to the detail page. Following is an example data table in the master page /products/list.xhtml based on a fictive Product entity :

<h:dataTable value="#{listProducts.products}" var="product">
    <h:column>#{product.id}</h:column>
    <h:column>#{product.name}</h:column>
    <h:column>#{product.description}</h:column>
    <h:column>
        <h:link value="Edit" outcome="edit">
            <f:param name="id" value="#{product.id}" />
        </h:link>
    </h:column>
</h:dataTable>

Note the last column of the table . It generates a link to the detail page /products/edit.xhtml whereby the ID of the entity is passed as a GET request parameter as in /product.xhtml?id=42. In the detail page, you can use <f:viewParam> to set the GET request parameter in the backing bean.

<f:metadata>
    <f:viewParam name="id" value="#{editProduct.product}"
        required="true" requiredMessage="Bad request">
    </f:viewParam>
</f:metadata>
...
<h:form>
    <h1>Edit product #{editProduct.product.id}</h1>
    <h:inputText value="#{editProduct.product.name}" />
    <h:inputText value="#{editProduct.product.description}" />
    ...
</h:form>

However, there’s one small problem: the GET request parameter is in Java perspective basically a String representing the product ID while the product property of the EditProduct backing bean actually expects a whole Product entity identified by the passed-in ID.

@Named @ViewScoped
public class EditProduct implements Serializable {


    private Product product;

    // Getter+setter.
}

For exactly this conversion step, a custom converter has to be created which is capable of converting between a String representing the product ID and an Object representing the Product entity. JSF offers the javax.faces.convert.Converter interface20 to get started. Following is a concrete example of such a ProductConverter:

@FacesConverter(forClass=Product.class, managed=true)
public class ProductConverter implements Converter<Product> {


    @Inject
    private ProductService productService;


    @Override
    public String getAsString
        (FacesContext context, UIComponent component, Product product)
    {
        if (product == null) {
            return "";
        }


        if (product.getId() != null) {
            return product.getId().toString();
        }
        else {
            throw new ConverterException(
                new FacesMessage("Invalid product ID"), e);
        }
    }


    @Override
    public Product getAsObject
         (FacesContext context, UIComponent component, String id)
    {
        if (id == null || id.isEmpty()) {
            return null;
        }


        try {
            return productService.getById(Long.valueOf(id));
        }
        catch (NumberFormatException e) {
            throw new ConverterException(
                new FacesMessage("Invalid product ID"), e);
        }
    }
}

There are several important things to note here in the @FacesConverter annotation . First, the forClass attribute basically specifies the target entity type for which this converter should automatically run during the process validations phase (third phase) and the render response phase (sixth phase). This way you don’t need to explicitly register the converter in the view. In case you wanted to do so, you’d replace the forClass attribute by the value attribute specifying the unique identifier of the converter, for example:

@FacesConverter(value="project.ProductConverter", managed=true)

Then you can specify exactly that converter ID in the converter attribute of any ValueHolder component, or the converterId attribute of any nested <f:converter> tag.

<f:viewParam name="id" value="#{editProduct.product}"
    converter="project.ProductConverter"
    required="true" requiredMessage="Bad request">
</f:viewParam>

But this is not necessary when you just keep using the forClass attribute. Note that you can’t specify both. It’s one or the other where the value attribute takes precedence over the forClass. So, if you specify both, the forClass attribute is essentially ignored. We don’t want to have that as it’s much more powerful for this particular purpose of transparently converting whole entities.

The second thing to note in the annotation is the managed attribute. This is new since JSF 2.3. Essentially, this manages the converter instance in the CDI context. Setting the managed attribute to true is mandatory in order to get dependency injection to work in the converter. Previously, this was worked around by making the converter itself a managed bean.21

If you have worked with JSF converters before, you’ll also notice the interface now finally being parameterized. The interface predates Java 1.5 and was hence not parameterized from the beginning. With a Converter<T>, the getAsObject() now returns a T instead of Object and the getAsString() now takes a T as value argument instead of Object. This saves unnecessary instanceof checks and/or casts.

Note that JSF’s own standard converters which predate JSF 2.3 (currently, basically all of them thus) are frozen in time and cannot take advantage of this as they would otherwise no longer be backward compatible. In other words, they are still raw types. That is, there’s a small but not unavoidable chance that someone is programmatically using JSF converters in plain Java code instead of letting JSF deal with them. That plain Java code would no longer compile if the standard converters were parameterized. It’s essentially the same reason that the Map#get() explicitly takes Object instead of K as argument. Further there’s a yet smaller but still not unavoidable chance that someone has created a custom converter which extends a standard converter, but also explicitly redeclares the interface. Something like the following:

public class ExtendedNumberConverter
    extends NumberConverter implements Converter
{
    // ...
}

Such an obscure converter would no longer compile if NumberConverter was parameterized in some way. Even if we parameterize NumberConverter as a Converter<Object>, the compiler would error on ExtendedNumberConverter as follows and hence break backward compatibility:

The interface Converter cannot be implemented more than once with different arguments: Converter<Object> and Converter

Coming back to our ProductConverter implementation, in the getAsString() you’ll notice that the converter explicitly returns an empty string when the model value is null. This is as per the Javadoc.22 The technical reason is that JSF won’t render the associated HTML attribute when the evaluated value is null. In general, this is not a big problem. The fewer unused attributes in the generated HTML output, the better it is. Only, this won’t work as expected for the <option> of a <select> element. If the custom converter would return null instead of an empty string, then the <option> element would be rendered without any value attribute and thus fall back to submitting its text content instead. Awkward indeed, but this is literally specified in the HTML specification.23 In other words, if you have a converter that incorrectly returns null instead of an empty string , and you have a drop-down list with the associated entities along with a default option as follows:

<h:selectOneMenu value="#{bean.product}">
    <f:selectItem itemValue="#{null}" itemLabel="Please select ..." />
    <f:selectItems value="#{bean.products}"
        var="product" itemLabel="#{product.name}">
    </f:selectItems>
</h:selectOneMenu>

then the web browser would, during submitting the default option, send the literal string “Please select …” to the server instead of an empty string. This would cause a NumberFormatException in ProductConverter#getAsObject() while we intend to return null here. The correct solution is thus to let the getAsString() return an empty string in case the model value is null.

In case you have more persistence entities for which you need a JSF converter, and want to avoid repeating essentially the same ProductConverter logic for all other persistence entities, you can create a generic JSF converter for them. This works only if all your persistence entities extend from the same base class wherein the getId() is defined.

@MappedSuperClass
public abstract class BaseEntity implements Serializable {


    @Id @GeneratedValue(strategy=IDENTITY)
    private Long id;


    public Long getId() {
        return id;
    }
}

And if you have a base entity service for all of them:

@Stateless
public class BaseEntityService {


    @PersistenceContext
    private EntityManager entityManager;


    @TransactionAttribute(SUPPORTS)
    public <E extends BaseEntity> E getById(Class<E> type, Long id) {
        return entityManager.find(type, id);
    }
}

the generic converter can then look as follows:

@FacesConverter(forClass=BaseEntity.class, managed=true)
public class BaseEntityConverter implements Converter<BaseEntity> {


    @Inject
    private BaseEntityService baseEntityService;


    @Override
    public String getAsString
        (FacesContext context, UIComponent component, BaseEntity entity)
    {
        if (entity == null) {
            return "";
        }


        if (entity.getId() != null) {
            return entity.getId().toString();
        }
        else {
            throw new ConverterException(
                new FacesMessage("Invalid entity ID"), e);
        }
    }


    @Override
    public BaseEntity getAsObject
         (FacesContext context, UIComponent component, String id)
    {
        if (id == null || id.isEmpty()) {
            return null;
        }


        ValueExpression value = component.getValueExpression("value");
        Class<? extends BaseEntity> type = (Class<? extends BaseEntity>)
            value.getType(context.getELContext());


        try {
            return baseEntityService.getById(type, Long.valueOf(id));
        }
        catch (NumberFormatException e) {
            throw new ConverterException(
                new FacesMessage("Invalid entity ID"), e);
        }
    }
}

The key here is thus the ValueExpression#getType() call. This returns the actual type of the property behind the EL expression associated with the component’s value attribute. In case of <f:viewParam value="#{editProduct.product}"> this would thus return Product.class, which fits Class<? extends BaseEntity>.

Coming back to the less common use case of a custom converter, extending a standard converter, imagine that you have a <f:convertDateTime> configuration which is repeated everywhere in your web application :

<f:convertDateTime type="localDate" pattern="yyyy-MM-dd" />

And you’d like to replace it with something like the following:

<t:convertLocalDate />

Then one way is to just extend it, set the defaults in the constructor, register it in the *.taglib.xml file, and that’s it. Following is what such a LocalDateConverter can look like:

@FacesConverter("project.ConvertLocalDate")
public class LocalDateConverter extends DateTimeConverter {


    public LocalDateConverter() {
        setType("localDate");
        setPattern("yyyy-MM-dd");
    }
}

And here’s the /WEB-INF/example.taglib.xml entry.

<tag>
    <tag-name>convertLocalDate</tag-name>
    <converter>
        <converter-id>project.ConvertLocalDate</converter-id>
    </converter>
</tag>

Alternatively, you can also make it an implicit converter by getting rid of the converter ID and making it a forClass converter.

@FacesConverter(forClass=LocalDate.class)

This way you don’t even need any <t:convertLocalDate> tag. Don’t forget to remove the <tag> entry in example.taglib.xml. They cannot be used simultaneously. If you need such case, for example, because you want to able to change the LocalDate pattern, create another subclass.

You can even have a forClass converter for java.lang.String typed properties . This is very useful when you want have an automatic application-wide string-trimming strategy which should prevent the model from being polluted with leading or trailing whitespace on user-submitted values. Following is what such a converter can look like:

@FacesConverter(forClass=String.class)
public class TrimConverter implements Converter<String> {


    @Override
    public String getAsString
        (FacesContext context, UIComponent component, String modelValue)
    {
        return modelValue == null ? "" : modelValue;
    }


    @Override
    public String getAsObject(FacesContext context,
        UIComponent component, String submittedValue)
    {
        if (submittedValue == null || submittedValue.isEmpty()) {
            return null;
        }


        String trimmed = submittedValue.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }
}

Last but not least, when you need to provide whole entities as SelectItem values of a selection component as below (see also Chapter 4), along with a custom converter for Country.class:

<h:selectOneMenu value="#{bean.country}">
    <f:selectItem itemValue="#{null}" itemLabel="-- select one --" />
    <f:selectItems value="#{bean.availableCountries}" var="country">
        itemValue="#{country}" itemLabel="#{country.name}"
    </f:selectItems>
</h:selectOneMenu>

where the associated backing bean properties are declared as follows:

private Country country;
private List<Country> availableCountries;

then you need to keep in mind that the entity has its equals() and hashCode() properly implemented. Otherwise JSF may throw a confusing validation error when submitting the form.

Validation Error: Value is not valid

This may happen when the bean is request scoped instead of view scoped and thus recreates the list of available countries during every postback. As part of safeguard against tampered requests, JSF will reiterate over the available options in order to validate if the selected option is indeed among them. JSF will use the Object#equals() method to test the selected option against each available option. If this hasn’t returned true for any of the available options, then the above-mentioned validation error will be thrown.

Continuing with the BaseEntity example, here’s how you’d best implement its equals() and hashCode() methods .

@Override
public boolean equals(Object other) {
    if (getId() != null
        && getClass().isInstance(other)
        && other.getClass().isInstance(this))
    {
        return getId().equals(((BaseEntity) other).getId());
    }
    else {
        return (other == this);
    }
}


@Override
public int hashCode() {
    if (getId() != null) {
        return Objects.hash(getId());
    }
    else {
        return super.hashCode();
    }
}

Note the bidirectional Class#isInstance() test in the equals() method . This is done instead of getClass() == other.getClass(), because that would return false when your persistence framework uses proxies, such as Hibernate.

Custom Validators

Also, validators can be customized in JSF from the beginning. As almost every every basic use case is already covered by standard JSF validators and even Bean Validation constraints, such as length, range, and pattern validation, the most common use case left to a custom JSF validator is validating the data integrity by testing the submitted value against database-based constraints. Generally, those concern unique constraints.

A good real-world example is validating during e-mail-based signup or while changing the e-mail address in the user account management page when the specified e-mail address is not already in use. Particularly, the change event can’t be tested with a Bean Validation constraint in a simple way, because Bean Validation doesn’t offer the opportunity to compare the old value with the new value without re-obtaining the entity from the database. To start, just implement the javax.faces.validator.Validator interface24 accordingly.

@FacesValidator(value="project.UniqueEmailValidator", managed=true)
public class UniqueEmailValidator implements Validator<String> {


    @Inject
    private UserService userService;


    @Override
    public void validate
        (FacesContext context, UIComponent component, String email)
            throws ValidatorException
    {
        if (email == null || email.isEmpty()) {
            return; // Let @NotNull or required=true handle this.
        }


        String oldEmail = (String) ((UIInput) component).getValue();

        if (!email.equals(oldEmail) && userService.exist(email)) {
            throw new ValidatorException(
                new FacesMessage("Email already in use"));
        }
    }
}

In order to get it to run, just specify exactly the declared validator ID in the validator attribute of any EditableValueHolder component, or the validatorId attribute of any nested <f:validator> tag.

<h:inputText value="#{signup.user.email}"
    validator="project.UniqueEmailValidator">
</h:inputText>

When looking at the UniqueEmailValidator class, you’ll notice that the annotation and the interface also got the same JSF 2.3 changes as the converter. Like the @FacesConverter, the @FacesValidator annotation, since JSF 2.3, also got a new managed attribute which should enable dependency injection in the validator implementation. And, like the Converter<T>, the Validator<T> also got parameterized whereby the validate() method now takes a T instead of Object as a value argument.

You also need to make sure that your validators are implemented so that they skip validation when the value argument is null or empty. Historically, in JSF 1.x, the validate() method would always be skipped when the value argument is null. However, this has changed since the integration of Bean Validation in JSF 2.0, thereby breaking backward compatibility on existing JSF 1.x-based custom validators. This breaking change could be turned off by explicitly setting the following web.xml context parameter:

<context-param>
    <param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
    <param-value>false</param-value>
</context-param>

The disadvantage of this is that the @NotNull of Bean Validation won’t be triggered by JSF and you’d basically need to repeat this constraint for all JSF input components by explicitly setting their required attribute to true. You’d better not do this and just keep performing the null and empty check in your custom validator. Having validation constraints at a single place in the model with help of Bean Validation is more Don’t Repeat Yourself (DRY) than repeating the validation constraints across different layers using the very same model.

Finally, the old value can simply be obtained from UIInput#getValue() which basically returns the current value attribute of the UIInput component.

Coming back to the use case of validating the uniqueness of the submitted value, of course you could also skip this and insert the data anyway and catch any constraint violation exception coming from the persistence layer and display a faces message accordingly. However, this doesn’t go well with the current trend of immediate feedback directly after changing the input field in the user interface.

In this specific use case of validating a unique e-mail address during signup, however, there may be another reason not to give away too much detail about the uniqueness of the specified e-mail address: security. In such a case, you’d best let the signup complete exactly the same way as if it was successful whereby you tell the user to check the mailbox, but behind the scenes actually send a different e-mail to the target recipient, rather than an activation e-mail, preferably not more than once daily. The e-mail would be similar to the following:

Dear user,

It looks like you or someone else tried to sign up on our web site using your email address [email protected] while it is already associated with an existing account. Perhaps you actually wanted to log in or to reset your password ? If it actually wasn’t you, please let us know by replying to this email and we’ll investigate this.

Sincerely, Example Company

Finally, you might also want to consider invalidating or deduplicating e-mails that contain the “+” character in the username part, followed by a sequence of characters, representing an e-mail alias. For a lot of e-mail providers, notably Gmail, e-mail addresses [email protected] and [email protected] refer to exactly the same e-mail account, thereby basically allowing the end user to create a nearly unlimited amount of accounts.

Custom Constraints

While not part of the JSF, for the sake of completeness we’d like to show another example of a custom Bean Validation constraint . An earlier example was already given in the section about <f:validateWholeBean>. The Bean Validation API already offers a lot of existing constraints out of the box which you can find in the javax.validation.constraints package.25 A lot of new constraints have been added in Bean Validation 2.0, also part of Java EE 8 like JSF 2.3, such as @Email.

Most common use cases for a custom Bean Validation constraint are related to localized patterns. Think of phone numbers, zip codes, bank account numbers, and passwords. Of course, most of those could be done with just a @Pattern, but this may end up in less self-documenting code , particularly if the desired pattern is relatively complex.

Following is an example of a custom @Phone constraint which should match as many as possible internationally known phone numbers:

@Constraint(validatedBy=PhoneValidator.class)
@Target(FIELD)
@Retention(RUNTIME)
public @interface Phone {
    String message() default "Invalid phone number";
    Class<?>[] groups() default {};
    Class<?>[] payload() default {};
}

And here’s the associated PhoneValidator:

public class PhoneValidator
    implements ConstraintValidator<Phone, String>
{
    private static final Pattern SPECIAL_CHARS =
        Pattern.compile("[\s().+-]|ext", Pattern.CASE_INSENSITIVE);
    private static final Pattern DIGITS =
        Pattern.compile("[0-9]{7,15}");


    @Override
    public boolean isValid
        (String phone, ConstraintValidatorContext context)
    {
        if (phone == null || phone.isEmpty()) {
            return true; // Let @NotNull/@NotEmpty handle this.
        }


        return isValid(phone);
    }


    public static boolean isValid(String phone) {
        String digits = SPECIAL_CHARS.matcher(phone).replaceAll("");
        return DIGITS.matcher(digits).matches();
    }
}

In order to activate it, simply annotate the associated entity property.

@Phone
private String phone;

This will be triggered on both the JSF and JPA sides: in JSF, during the process validations phase (third phase); in JPA during the persist and merge. As noted in the <f:validateBean>/<f:validateWholeBean> section, it can be disabled on both sides.

Custom Messages

Conversion and validation error messages coming from JSF as well as Bean Validation are fully customizable. Application-wide, they can be customized by supplying a properties file which specifies the desired message as the value of a predefined key. You can find predefined keys for JSF conversion and validation messages in Chapter 2.5.2.4, “Localized Application Messages,” of the JSF 2.3 specification.26 You can find predefined keys for Bean Validation messages in Appendix B, “Standard ResourceBundle Messages,” of the Bean Validation 2.0 specification.27 For JSF, the fully qualified name of the properties file must be registered as <message-bundle> in faces-config.xml. For Bean Validation, the exact fully qualified name of the properties file is ValidationMessages.

As an example, we’re going to modify the default message of the JSF required="true" validation and the Bean Validation @NotNull constraint.

main/java/resources/com/example/project/i18n/messages.properties
javax.faces.component.UIInput.REQUIRED = {0} is required.
javax.faces.validator.BeanValidator.MESSAGE = {1} {0}
main/java/resources/ValidationMessages.properties
javax.validation.constraints.NotNull.message = is required.

Note the absence of the label placeholder in the Bean Validation message. Instead, the {1} of the javax.faces.validator.BeanValidator.MESSAGE represents the label associated with the JSF component and {0} represents the Bean Validation message. The custom Bean Validation message bundle file is already automatically picked up. The custom JSF message bundle file needs to be explicitly registered in the faces-config.xml first.

<application>
    <message-bundle>com.example.project.i18n.messages</message-bundle>
</application>

With those properties files in place, the following input components will thus show exactly the same validation error message:

<h:inputText id="field" label="First input"
    value="#{bean.field}" required="true">
</h:inputText>
<h:message for="field" />


<h:inputText id="notNullField" label="Second input"
    value="#{bean.notNullField}">
</h:inputText>
<h:message for="notNullField" />

In case you want to fine-grain the message on a per-component basis, you can use the converterMessage, validatorMessage, and/or requiredMessage attribute of the UIInput component. The converterMessage will be displayed on any conversion error .

<h:inputText value="#{bean.localDate}"
    converterMessage="Please enter date in pattern YYYY-MM-DD.">
    <f:convertLocalDate type="localDate" pattern="yyyy-MM-dd" />
</h:inputText>

The validatorMessage will be displayed on any validation error, as well as those triggered by Bean Validation.

<h:inputText value="#{bean.dutchZipCode}" required="true"
    validatorMessage="Please enter zip code in pattern 1234AB.">
    <f:validateRegex pattern="[0-9]{4}[A-Z]{2}" />
</h:inputText>

Note that this won’t be shown when required="true" isn’t satisfied. For that, you need to use requiredMessage instead.

<h:inputText value="#{bean.dutchZipCode}" required="true"
    requiredMessage="Please enter zip code."
    validatorMessage="Please enter zip code in pattern 1234AB.">
    <f:validateRegex pattern="[0-9]{4}[A-Z]{2}" />
</h:inputText>

Note that this won’t be shown for any Bean Validation @NotNull. You should then use validatorMessage instead.

Footnotes

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.193.210