Adding your own validators

Note
The following guide for building custom validators assumes that you are familiar with the notion of Calyxo Forms validators (i.e., matchers, converters and checkers) as it is illustrated in the concepts section.

Before writing your own validator, you should make sure that none of the predefined validators suites your needs. For two of the three validator types, there are already very powerful validation mechanisms at your hand: 1. the regexp matcher matches against an arbitrary regular expression, which means that you can handle a large class of string validations, 2. the el checker checks the converted input value using an arbitrary EL expression, so it might be a better solution to write a custom function (see Calyxo Base extensions) and use it in an EL expression. So, if these considerations didn't make you change your mind, don't hesitate to read on.

Technically, writing a new validator means to write a Java class which implements one of the Calyxo Forms validator interfaces (all of them can be found in the de.odysseus.calyxo.forms package). As you might expect:

We'll have a closer look at those interfaces below, but first let's concentrate on the main ideas. Basically, when writing a new validator, you have to work out one or two methods, which define the behavior of your validator. Depending on the validator type, these are:

Validator Type Method Name Description
Matcher match(...) Processes its input string and returns a result string, usually the matched portion of the input string, which will be passed to the next validator in the validation sequence. If the matching fails, null is returned.
Converter parse(...) Parses its input string and returns an arbitrary result value, which will be passed to the first checker in the validation sequence, if there is one. If the parsing fails, a ParseException is thrown.
Converter format(...) Formats the given value from the data bean into its string representation. (This is not actually an act of validation, but its obviously a task, which has to be handled at the same place, since after parsing a formatted value the resulting value should not have changed.)
Checker check(...) Performs arbitrary tests on its input value and returns a boolean value of true, if it passed all tests successfully, and false otherwise.

After implementing your validator it has to be declared in the <validators> section of the Calyxo Forms configuration file, where it will be used. The declaration of a validator defines its name, its properties and the corresponding error message.

Example

The following code illustrates the implementation of a simple CurrencyConverter, which converts a string to an instance of java.util.Currency and vice versa. If the string to be parsed is empty, the string value of the property named default is parsed instead (whereas a null currency is formatted to a null string).

package my.validators;

import java.text.ParseException;
import java.util.Currency;
import de.odysseus.calyxo.forms.convert.SimpleConverter;

public class CurrencyConverter extends SimpleConverter {
  private String default;

  public CurrencyConverter() {
    super();
  }
  public String format(Object value) {
    if (value == null) {
      return null;
    }
    return ((Currency) value).toString();
  }
  public Object parse(String value) throws ParseException {
    if (value == null) {
      value = default;
    }
    try {
      return Currency.getInstance(value);
    } catch (IllegalArgumentException e) {
      throw new ParseException("Cannot parse: " + value, 0);
    }
  }
  public String getDefault() {
    return default;
  }
  public void setDefault(String value) {
    default = value;
  }
}

Here we use the convenience base class de.odysseus.calyxo.forms.convert.SimpleConverter, which implements the Converter interface mentioned above. It declares two abstract methods, which have to be overridden with concrete versions: public abstract Object parse(String value) throws ParseException and public abstract String format(Object value).

This converter is declared in a Calyxo Forms configuration file by adding a <converter> element to the <validators> section as shown below:

<validators>
  <converter id="currency" class="my.validators.CurrencyConverter">
    <property name="default" value="EUR"/>
    <message key="error.parse.currency" bundle="foo.msg">
      <arg name="field"/>
    </message>
  </converter>
</validators>

Now the converter is accessible in the <forms> section under the name currency, has a property called default (preset to "EUR") and a predefined error message. The error message has to be added to the msg.properties file with an entry like error.parse.currency=Field '{0}' must be a valid currency and offers the argument named field to be filled with the actual field name when used:

<forms>
  <form name="currencyForm">
    <field property="preferredCurrency">
      <convert name="currency">
        <property name="default" value="USD"/>
        <message>
          <arg name="field" value="Preferred Currency"/>
        </message>
      </convert>
    </field>
  <form>
</forms>

In this case we override the default currency with the value "USD", use the predefined error message and just set the field name to the value "Preferred Currency", which causes the displayed error message to be Field 'Preferred Currency' must be a valid currency.