jp.terasoluna.fw.validation.FieldChecks.java Source code

Java tutorial

Introduction

Here is the source code for jp.terasoluna.fw.validation.FieldChecks.java

Source

/*
 * Copyright (c) 2007 NTT DATA Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jp.terasoluna.fw.validation;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import jp.terasoluna.fw.beans.IndexedBeanWrapper;
import jp.terasoluna.fw.beans.JXPathIndexedBeanWrapperImpl;
import jp.terasoluna.fw.util.BeanUtil;
import jp.terasoluna.fw.util.ClassLoadException;
import jp.terasoluna.fw.util.ClassUtil;
import jp.terasoluna.fw.util.PropertyAccessException;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericTypeValidator;
import org.apache.commons.validator.GenericValidator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.ValidatorException;
import org.apache.commons.validator.util.ValidatorUtils;

/**
 * TERASOLUNA?????
 *
 * ???????????????</p>
 *
 * <table border="1">
 * <tr>
 *  <td><center><b>??</b></center></td>
 *  <td><center><b>??</b></center></td>
 *  <td><center><b>?validation.xml?
 *  ???</b></center></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateRequired(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>requierd</code></td>
 * </tr>
 * <tr>
 *  <td>???</td>
 *  <td><code>{@link #validateMask(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>mask</code></td>
 * </tr>
 * <tr>
 *  <td><code>byte</code>?</td>
 *  <td><code>{@link #validateByte(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>byte</code></td>
 * </tr>
 * <tr>
 *  <td><code>short</code>?</td>
 *  <td><code>{@link #validateShort(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>short</code></td>
 * </tr>
 * <tr>
 *  <td><code>integer</code>?</td>
 *  <td><code>{@link #validateInteger(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>integer</code></td>
 * </tr>
 * <tr>
 *  <td><code>long</code>?</td>
 *  <td><code>{@link #validateLong(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>long</code></td>
 * </tr>
 * <tr>
 *  <td><code>float</code>?</td>
 *  <td><code>{@link #validateFloat(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>float</code></td>
 * </tr>
 * <tr>
 *  <td><code>double</code>?</td>
 *  <td><code>{@link #validateDouble(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>double</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateDate(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>date</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateIntRange(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>intRange</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateDoubleRange(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>doubleRange</code></td>
 * </tr>
 * <tr>
 *  <td>??</td>
 *  <td><code>{@link #validateFloatRange(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>floatRange</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateMaxLength(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>maxLength</code></td>
 * </tr>
 * <tr>
 *  <td>??</td>
 *  <td><code>{@link #validateMinLength(
 *  Object, ValidatorAction, Field, ValidationErrors)}</code></td>
 *  <td><code>minLength</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateAlphaNumericString(Object, ValidatorAction,
 *  Field, ValidationErrors)}</code></td>
 *  <td><code>alphaNumericString</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateCapAlphaNumericString(Object, ValidatorAction,
 *  Field, ValidationErrors)}</code></td>
 *  <td><code>capAlphaNumericString</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateNumber(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td><code>number</code></td>
 * </tr>
 * <tr>
 *  <td>??</td>
 *  <td><code>{@link #validateHankakuKanaString(Object, ValidatorAction,
 *  Field, ValidationErrors)}</code></td>
 *  <td><code>hankakuKanaString</code></td>
 * </tr>
 * <tr>
 *  <td>??</td>
 *  <td><code>{@link #validateHankakuString(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td><code>hankakuString</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateZenkakuKanaString(Object, ValidatorAction,
 *  Field, ValidationErrors)}</code></td>
 *  <td><code>zenkakuKanaString</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateZenkakuString(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td><code>zenkakuString</code></td>
 * </tr>
 * <tr>
 *  <td>??</td>
 *  <td><code>{@link #validateProhibited(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td><code>prohibited</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateStringLength(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td><code>stringLength</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateNumericString(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td><code>numericString</code></td>
 * </tr>
 * <tr>
 *  <td>URL?</td>
 *  <td><code>{@link #validateUrl(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td><code>url</code></td>
 * </tr>
 * <tr>
 *  <td>??</td>
 *  <td><code>{@link #validateArrayRange(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td><code>arrayRange</code></td>
 * </tr>
 * <tr>
 *  <td>??</td>
 *  <td><code>{@link #validateByteRange(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td><code>byteRange</code></td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateDateRange(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td><code>dateRange</code></td>
 * </tr>
 * <tr>
 *  <td>???</td>
 *  <td><code>{@link #validateArraysIndex(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td>????"Array"(?????)</td>
 * </tr>
 * <tr>
 *  <td>?</td>
 *  <td><code>{@link #validateMultiField(Object, ValidatorAction, Field,
 *  ValidationErrors)}</code></td>
 *  <td>multiField</td>
 * </tr>
 * </table>
 *
 * <p>????Struts?ValidWhen???
 * ?????????????
 * ????????</p>
 *
 * <p>??????
 * ???????????????????
 * ????????????
 * ??????</p>
 * 
 * <p>?????????????
 * ?(validation.xml) ?????</p>
 *
 * <h5>validation.xml??</h5>
 * <code><pre>
 *  &lt;formset&gt;
 *    
 *    &lt;!-- ?? --&gt;
 *    &lt;form name="testBean"&gt;
 *      &lt;field property="field"
 *          depends="required,alphaNumericString,maxlength"&gt;
 *        &lt;arg key="testBean.field" position="0"/&gt;
 *        &lt;arg key="${var:maxlength}" position="1"/&gt;
 *        &lt;var&gt;
 *          &lt;var-name&gt;maxlength&lt;/var-name&gt;
 *          &lt;var-value&gt;10&lt;/var-value&gt;
 *        &lt;/var&gt;
 *      &lt;/field&gt;
 *    &lt;/form&gt;
 *    
 *  &lt;/formset&gt;
 * </pre></code>
 *
 * <h5>???</h5>
 *
 * <p>???
 * {@link #validateArraysIndex(
 * Object, ValidatorAction, Field, ValidationErrors)}
 * ?????????
 * ???</p>
 *
 * <p>???fields???????bean????
 * fields????????validation.xml????
 * fields??
 * ?????fields????????
 * ??????
 * ?validation.xml?depends??????Array?
 * ??????</p>
 *
 * ????????
 * <ul>
 *   <li><code>requiredArray</code></li>
 *   <li><code>minLengthArray</code></li>
 *   <li><code>maxLengthArray</code></li>
 *   <li><code>maskArray</code></li>
 *   <li><code>byteArray</code></li>
 *   <li><code>shortArray</code></li>
 *   <li><code>integerArray</code></li>
 *   <li><code>longArray</code></li>
 *   <li><code>floatArray</code></li>
 *   <li><code>doubleArray</code></li>
 *   <li><code>dateArray</code></li>
 *   <li><code>intRangeArray</code></li>
 *   <li><code>doubleRangeArray</code></li>
 *   <li><code>floatRangeArray</code></li>
 *   <li><code>creditCardArray</code></li>
 *   <li><code>emailArray</code></li>
 *   <li><code>urlArray</code></li>
 *   <li><code>alphaNumericStringArray</code></li>
 *   <li><code>hankakuKanaStringArray</code></li>
 *   <li><code>hankakuStringArray</code></li>
 *   <li><code>zenkakuStringArray</code></li>
 *   <li><code>zenkakuKanaStringArray</code></li>
 *   <li><code>capAlphaNumericStringArray</code></li>
 *   <li><code>numberArray</code></li>
 *   <li><code>numericStringArray</code></li>
 *   <li><code>prohibitedArray</code></li>
 *   <li><code>stringLengthArray</code></li>
 *   <li><code>dateRangeArray</code></li>
 *   <li><code>byteRangeArray</code></li>
 * </ul>
 *
 * <p>????????
 * ???</p>
 *
 * <p>?????????
 * <ul>
 *   <li></li>
 *   <li>?????</li>
 *   <li>?</li>
 * </ul>
 * </p>
 *
 * @see jp.terasoluna.fw.beans.JXPathIndexedBeanWrapperImpl
 * @see jp.terasoluna.fw.beans.IndexedBeanWrapper
 */
public class FieldChecks {

    /**
     * ??
     */
    private static Log log = LogFactory.getLog(FieldChecks.class);

    /**
     * ?Null??????0????
     * ?
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     */
    public boolean validateRequired(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);

        // 
        if (GenericValidator.isBlankOrNull(value)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ???????????
     *
     * <p>???????????true??
     * ???
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;maskField&quot;
     *      depends=&quot;mask&quot;&gt;
     *    &lt;arg key=&quot;sample.escape&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;mask&lt;/var-name&gt;
     *      &lt;var-value&gt;^([0-9]|[a-z]|[A-Z])*$&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     *
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> mask </td>
     *   <td>??</td>
     *   <td>true</td>
     *   <td>???????????? <code>true</code>
     *       ????????ValidatorException
     *       ??</td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     * @exception ValidatorException ?mask(??)??
     * ?????????
     */
    public boolean validateMask(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // ??
        String mask = field.getVarValue("mask");

        // var?mask?????????ValidatorException
        if (StringUtils.isEmpty(mask)) {
            log.error("var[mask] must be specified.");
            throw new ValidatorException("var[mask] must be specified.");
        }

        // 
        if (!GenericValidator.matchRegexp(value, mask)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ?byte?????
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     */
    public boolean validateByte(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (GenericTypeValidator.formatByte(value) == null) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ?short?????
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     */
    public boolean validateShort(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (GenericTypeValidator.formatShort(value) == null) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ?int?????
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     */
    public boolean validateInteger(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (GenericTypeValidator.formatInt(value) == null) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ?long?????
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     */
    public boolean validateLong(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (GenericTypeValidator.formatLong(value) == null) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ?float?????
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     */
    public boolean validateFloat(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (GenericTypeValidator.formatFloat(value) == null) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ?double?????
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     */
    public boolean validateDouble(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (GenericTypeValidator.formatDouble(value) == null) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ????
     *
     * <p>field?datePattern???????
     * <code>java.text.SimpleDateFormat</code>
     * ?????</p>
     *
     * <p>field?datePatternStrict???????
     * <code>java.text.SimpleDateFormat</code>???
     * ????
     * ???'2/12/1999'?'MM/dd/yyyy'?????
     * Month)??????????</p>
     *
     * <p>datePattern???datePatternStrict?????
     * ??datePattern?????
     *  datePattern???datePatternStrict????????
     *  ??????????????
     *  ???</p>
     *
     * <p>???setLenient=false??????
     * 2000/02/31???????????????</p>
     *
     * ???yyyy/MM/dd??????
     * ?????
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;dateField&quot;
     *      depends=&quot;date&quot;&gt;
     *    &lt;arg key=&quot;sample.dateField&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;datePattern&lt;/var-name&gt;
     *      &lt;var-value&gt;yyyy/MM/dd&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     *
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> datePattern </td>
     *   <td></td>
     *   <td>false</td>
     *   <td>????????
     *   ??????yyyy/MM/dd???2001/1/1?????
     *   datePattern?datePatternStrict???????
     *   datePattern????
     *   </td>
     *  </tr>
     *  <tr>
     *   <td> datePatternStrict </td>
     *   <td></td>
     *   <td>false</td>
     *   <td>?????
     *   ???????????
     *   ??????yyyy/MM/dd???2001/1/1???
     *   datePattern?datePatternStrict???????
     *   datePattern????
     *   </td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     * @throws ValidatorException validation??????
     * ?
     */
    public boolean validateDate(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // ?
        String datePattern = field.getVarValue("datePattern");
        String datePatternStrict = field.getVarValue("datePatternStrict");

        // 
        Date result = null;
        try {
            result = ValidationUtil.toDate(value, datePattern, datePatternStrict);
        } catch (IllegalArgumentException e) {
            // ????
            String message = "Mistake on validation definition file. "
                    + "- datePattern or datePatternStrict is invalid. " + "You'll have to check it over. ";
            log.error(message, e);
            throw new ValidatorException(message);
        }
        if (result == null) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ???int??????
     * ??????
     *
     * <p>???10?100???????????
     * true?????
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;intField&quot;
     *      depends=&quot;intRange&quot;&gt;
     *    &lt;arg key=&quot;sample.intField&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;intRangeMin&lt;/var-name&gt;
     *      &lt;var-value&gt;10&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;intRangeMax&lt;/var-name&gt;
     *      &lt;var-value&gt;100&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     *
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> intRangeMin </td>
     *   <td>?</td>
     *   <td>false</td>
     *   <td>????????Integer???
     *   ?
     *   ????????</td>
     *  </tr>
     *  <tr>
     *   <td> intRangeMax </td>
     *   <td></td>
     *   <td>false</td>
     *   <td>???????Integer??
     *   ?
     *   ????????</td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     * @throws ValidatorException validation??????
     * ?
     */
    public boolean validateIntRange(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // int?? --- Integer??????
        int intValue = 0;
        try {
            intValue = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            rejectValue(errors, field, va, bean);
            return false;
        }

        //  --- ?Integer??????
        //                ????
        String strMin = field.getVarValue("intRangeMin");
        int min = Integer.MIN_VALUE;
        if (!GenericValidator.isBlankOrNull(strMin)) {
            try {
                min = Integer.parseInt(strMin);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- intRangeMin is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }
        String strMax = field.getVarValue("intRangeMax");
        int max = Integer.MAX_VALUE;
        if (!GenericValidator.isBlankOrNull(strMax)) {
            try {
                max = Integer.parseInt(strMax);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- intRangeMax is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }

        // 
        if (!GenericValidator.isInRange(intValue, min, max)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ???double??????
     * ??????
     *
     * <p>???10?100???????????
     * true?????
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;doubleField&quot;
     *      depends=&quot;doubleRange&quot;&gt;
     *    &lt;arg key=&quot;sample.doubleField&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;doubleRangeMin&lt;/var-name&gt;
     *      &lt;var-value&gt;10.0&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;doubleRangeMax&lt;/var-name&gt;
     *      &lt;var-value&gt;100.0&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     *
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> doubleRangeMin </td>
     *   <td>?</td>
     *   <td>false</td>
     *   <td>????????Double???
     *   ?
     *   ????????</td>
     *  </tr>
     *  <tr>
     *   <td> doubleRangeMax </td>
     *   <td></td>
     *   <td>false</td>
     *   <td>???????Double??
     *   ?
     *   ????????</td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     * @throws ValidatorException validation??????
     * ?
     */
    public boolean validateDoubleRange(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // double?? --- Double??????
        double dblValue = 0;
        try {
            dblValue = Double.parseDouble(value);
        } catch (NumberFormatException e) {
            rejectValue(errors, field, va, bean);
            return false;
        }

        //  --- ?Double??????
        //                ????
        String strMin = field.getVarValue("doubleRangeMin");
        double min = Double.MIN_VALUE;
        if (!GenericValidator.isBlankOrNull(strMin)) {
            try {
                min = Double.parseDouble(strMin);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- doubleRangeMin is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }
        String strMax = field.getVarValue("doubleRangeMax");
        double max = Double.MAX_VALUE;
        if (!GenericValidator.isBlankOrNull(strMax)) {
            try {
                max = Double.parseDouble(strMax);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- doubleRangeMax is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }

        // 
        if (!GenericValidator.isInRange(dblValue, min, max)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ???float??????
     * ??????
     *
     * <p>???10?100???????????
     * true?????
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;floatField&quot;
     *      depends=&quot;floatRange&quot;&gt;
     *    &lt;arg key=&quot;sample.floatField&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;floatRangeMin&lt;/var-name&gt;
     *      &lt;var-value&gt;10&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;floatRangeMax&lt;/var-name&gt;
     *      &lt;var-value&gt;100&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     *
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> floatRangeMin </td>
     *   <td>?</td>
     *   <td>false</td>
     *   <td>????????Float???
     *   ?
     *   ????????</td>
     *  </tr>
     *  <tr>
     *   <td> floatRangeMax </td>
     *   <td></td>
     *   <td>false</td>
     *   <td>???????Float??
     *   ?
     *   ????????</td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     * @throws ValidatorException validation??????
     * ?
     */
    public boolean validateFloatRange(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // float?? --- Float??????
        float floatValue = 0;
        try {
            floatValue = Float.parseFloat(value);
        } catch (NumberFormatException e) {
            rejectValue(errors, field, va, bean);
            return false;
        }

        //  --- ?Float??????
        //                ????
        String strMin = field.getVarValue("floatRangeMin");
        float min = Float.MIN_VALUE;
        if (!GenericValidator.isBlankOrNull(strMin)) {
            try {
                min = Float.parseFloat(strMin);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- floatRangeMin is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }
        String strMax = field.getVarValue("floatRangeMax");
        float max = Float.MAX_VALUE;
        if (!GenericValidator.isBlankOrNull(strMax)) {
            try {
                max = Float.parseFloat(strMax);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- floatRangeMax is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }

        // 
        if (!GenericValidator.isInRange(floatValue, min, max)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ??????
     *
     * <p>???10???????
     * true?????
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;stringField&quot;
     *      depends=&quot;maxLength&quot;&gt;
     *    &lt;arg key=&quot;sample.stringField&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;maxlength&lt;/var-name&gt;
     *      &lt;var-value&gt;10&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     *
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> maxlength </td>
     *   <td></td>
     *   <td>true</td>
     *   <td>??
     *   ????????</td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     * @throws ValidatorException validation??????
     * ?
     */
    public boolean validateMaxLength(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // ?
        int max = 0;
        try {
            max = Integer.parseInt(field.getVarValue("maxlength"));
        } catch (NumberFormatException e) {
            String message = "Mistake on validation definition file. " + "- maxlength is not number. "
                    + "You'll have to check it over. ";
            log.error(message, e);
            throw new ValidatorException(message);
        }

        // 
        if (!GenericValidator.maxLength(value, max)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ???????
     *
     * <p>???10???????
     * true?????
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;stringField&quot;
     *      depends=&quot;minLength&quot;&gt;
     *    &lt;arg key=&quot;sample.stringField&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;minlength&lt;/var-name&gt;
     *      &lt;var-value&gt;10&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     *
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> minlength </td>
     *   <td>?</td>
     *   <td>true</td>
     *   <td>???
     *   ????????</td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va ?<code>ValidatorAction</code>
     * @param field ?<code>Field</code>
     * @param errors ?????
     * ??
     * @return ??????<code>true</code>?
     * ????<code>false</code>?
     * @throws ValidatorException validation??????
     * ?
     */
    public boolean validateMinLength(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // ??
        int min = 0;
        try {
            min = Integer.parseInt(field.getVarValue("minlength"));
        } catch (NumberFormatException e) {
            String message = "Mistake on validation definition file. " + "- minlength is not number. "
                    + "You'll have to check it over. ";
            log.error(message, e);
            throw new ValidatorException(message);
        }

        // 
        if (!GenericValidator.minLength(value, min)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ?????????
     * ??<code>^([0-9]|[a-z]|[A-Z])*$</code>?
     * ??????????errors???
     * false??
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     */
    public boolean validateAlphaNumericString(Object bean, ValidatorAction va, Field field,
            ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (!ValidationUtil.isAlphaNumericString(value)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ?????????
     * ??????????errors???
     * false??
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     */
    public boolean validateCapAlphaNumericString(Object bean, ValidatorAction va, Field field,
            ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (!ValidationUtil.isUpperAlphaNumericString(value)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ?????????
     * ????
     * ??????????
     * errors???false??
     *
     * <p>???????BigDecimal ??
     * ???????????
     *
     * ??????????????
     * validation.xml ? isAccordedInteger()
     * ? "true" ??????
     * ??????
     * ?????????????
     *
     * ???????????????
     * validation.xml?isAccordedScale?"true"?????
     * ???????
     *
     * <p>
     * ??3??2?????
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;numberField&quot;
     *      depends=&quot;number&quot;&gt;
     *    &lt;arg key=&quot;sample.numberField&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;integerLength&lt;/var-name&gt;
     *      &lt;var-value&gt;3&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;scale&lt;/var-name&gt;
     *      &lt;var-value&gt;2&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;isAccordedInteger&lt;/var-name&gt;
     *      &lt;var-value&gt;true&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;isAccordedScale&lt;/var-name&gt;
     *      &lt;var-value&gt;true&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> <code>integerLength</code> </td>
     *   <td> ? </td>
     *   <td> <code>false</code> </td>
     *   <td>???<code>isAccordedInteger</code>?
     *       ?????????
     *       ???<code>int</code>???
     *       ???????</td>
     *  </tr>
     *  <tr>
     *   <td> <code>scale</code> </td>
     *   <td> ?? </td>
     *   <td> <code>false</code> </td>
     *   <td>?????<code>isAccordedScale</code>?
     *       ?????????
     *       ???<code>int</code>???
     *       ???????</td>
     *  </tr>
     *  <tr>
     *   <td> <code>isAccordedInteger</code> </td>
     *   <td> ?? </td>
     *   <td> <code>false</code> </td>
     *   <td> <code>true</code>???????????
     *        ????<code>true</code>?????
     *        ????</td>
     *  </tr>
     *  <tr>
     *   <td> <code>isAccordedScale</code> </td>
     *   <td> ??? </td>
     *   <td> <code>false</code> </td>
     *   <td> <code>true</code>????????????
     *        ????<code>true</code>?????
     *        ????</td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     * @throws ValidatorException validation??????
     * ?
     */
    public boolean validateNumber(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // ???????
        if (!ValidationUtil.isHankakuString(value)) {
            rejectValue(errors, field, va, bean);
            return false;
        }

        // BigDecimal??
        BigDecimal number = null;
        try {
            number = new BigDecimal(value);
        } catch (NumberFormatException e) {
            rejectValue(errors, field, va, bean);
            return false;
        }

        // ??
        int integerLength = Integer.MAX_VALUE;
        String integerLengthStr = field.getVarValue("integerLength");
        if (!GenericValidator.isBlankOrNull(integerLengthStr)) {
            try {
                integerLength = Integer.parseInt(integerLengthStr);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- integerLength is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }

        // ???
        int scaleLength = Integer.MAX_VALUE;
        String scaleStr = field.getVarValue("scale");
        if (!GenericValidator.isBlankOrNull(scaleStr)) {
            try {
                scaleLength = Integer.parseInt(scaleStr);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- scale is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }

        // ???
        boolean isAccordedInteger = "true".equals(field.getVarValue("isAccordedInteger"));
        // ????
        boolean isAccordedScale = "true".equals(field.getVarValue("isAccordedScale"));

        // 
        if (!ValidationUtil.isNumber(number, integerLength, isAccordedInteger, scaleLength, isAccordedScale)) {
            rejectValue(errors, field, va, bean);
            return false;
        }

        return true;
    }

    /**
     * ??????????
     * ??????????errors???
     * false??
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     */
    public boolean validateHankakuKanaString(Object bean, ValidatorAction va, Field field,
            ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (!ValidationUtil.isHankakuKanaString(value)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ??????????
     * ??????????errors???
     * false??
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     */
    public boolean validateHankakuString(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (!ValidationUtil.isHankakuString(value)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ?????????
     * ??????????errors???
     * false??
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     */
    public boolean validateZenkakuString(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (!ValidationUtil.isZenkakuString(value)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ???? ?????<br>
     * ??????????errors???
     * false??
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     */
    public boolean validateZenkakuKanaString(Object bean, ValidatorAction va, Field field,
            ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (!ValidationUtil.isZenkakuKanaString(value)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ?????????
     * ?????
     * ??????????errors???
     * false??
     *
     * <p>???????
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;stringField&quot;
     *      depends=&quot;prohibited&quot;&gt;
     *    &lt;arg key=&quot;sample.stringField&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;chars&lt;/var-name&gt;
     *      &lt;var-value&gt;!&quot;#$%&amp;'()&lt;&gt;&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> chars </td>
     *   <td>?</td>
     *   <td> true </td>
     *   <td>????????ValidatorException
     *   ??</td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     * @exception ValidatorException ?chars????????
     * ???
     */
    public boolean validateProhibited(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // ?
        String prohibitedStr = field.getVarValue("chars");

        // chars?????????ValidatorException
        if (StringUtils.isEmpty(prohibitedStr)) {
            log.error("var[chars] must be specified.");
            throw new ValidatorException("var[chars] must be specified.");
        }

        // 
        if (!ValidationUtil.hasNotProhibitedChar(value, prohibitedStr)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ??????????
     * ??????????errors???
     * false??
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     */
    public boolean validateNumericString(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        if (!ValidationUtil.isNumericString(value)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ???????????
     * ??????????errors???
     * false??
     *
     * <p>???5???????true??
     * ???
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;stringField&quot;
     *      depends=&quot;stringLength&quot;&gt;
     *    &lt;arg key=&quot;sample.stringField&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;stringLength&lt;/var-name&gt;
     *      &lt;var-value&gt;5&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> stringLength </td>
     *   <td></td>
     *   <td> false </td>
     *   <td>?
     *        ???<code>int</code>???</td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     * @throws ValidatorException validation??????
     * ?
     */
    public boolean validateStringLength(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        int length = Integer.MAX_VALUE;
        String lengthStr = field.getVarValue("stringLength");

        try {
            length = Integer.valueOf(lengthStr).intValue();
        } catch (NumberFormatException e) {
            String message = "Mistake on validation definition file. " + "- stringLength is not number. "
                    + "You'll have to check it over. ";
            log.error(message, e);
            throw new ValidatorException(message);
        }

        // 
        if (value.length() != length) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ????????
     * ???????
     * ??????????errors???
     * false??
     *
     * <p>?????????????true??
     * ???
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;arrayField&quot;
     *      depends=&quot;arrayRange&quot;&gt;
     *    &lt;arg key=&quot;sample.arrayField&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;minArrayLength&lt;/var-name&gt;
     *      &lt;var-value&gt;4&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;maxArrayLength&lt;/var-name&gt;
     *      &lt;var-value&gt;7&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> minArrayLength </td>
     *   <td>??</td>
     *   <td>false</td>
     *   <td>?????
     *        ???????????</td>
     *  </tr>
     *  <tr>
     *   <td> maxArrayLength </td>
     *   <td>?</td>
     *   <td>false</td>
     *   <td>????
     *        ???????
     *        <code>int</code>???</td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     * @throws ValidatorException validation??????
     * ?
     */
    public boolean validateArrayRange(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {

        // ??bean?null???ValidatorException
        if (bean == null) {
            String message = "target of validateArrayRange must be not null.";
            log.error(message);
            throw new ValidatorException(message);
        }

        try {
            Class<?> type = BeanUtil.getBeanPropertyType(bean, field.getProperty());
            if (type == null) {
                String message = "Cannot get property type[" + bean.getClass().getName() + "." + field.getProperty()
                        + "]";
                log.error(message);
                throw new ValidatorException(message);
            } else if (!type.isArray() && !Collection.class.isAssignableFrom(type)) {
                String message = "property [" + bean.getClass().getName() + "." + field.getProperty()
                        + "] must be instance of Array or Collection.";
                log.error(message);
                throw new ValidatorException(message);
            }
        } catch (PropertyAccessException e) {
            String message = "Cannot get property type[" + bean.getClass().getName() + "." + field.getProperty()
                    + "]";
            log.error(message, e);
            throw new ValidatorException(message);
        }

        // 
        Object obj = null;
        try {
            obj = BeanUtil.getBeanProperty(bean, field.getProperty());
        } catch (PropertyAccessException e) {
            String message = "Cannot get property [" + bean.getClass().getName() + "." + field.getProperty() + "]";
            log.error(message, e);
            throw new ValidatorException(message);
        }

        // ????
        int min = 0;
        String minStr = field.getVarValue("minArrayLength");
        if (!GenericValidator.isBlankOrNull(minStr)) {
            try {
                min = Integer.parseInt(minStr);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- minArrayLength is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }

        // ???
        int max = Integer.MAX_VALUE;
        String maxStr = field.getVarValue("maxArrayLength");
        if (!GenericValidator.isBlankOrNull(maxStr)) {
            try {
                max = Integer.parseInt(maxStr);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- maxArrayLength is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }

        // 
        try {
            if (!ValidationUtil.isArrayInRange(obj, min, max)) {
                rejectValue(errors, field, va, bean);
                return false;
            }
        } catch (IllegalArgumentException e) {
            log.error(e.getMessage());
            throw new ValidatorException(e.getMessage());
        }
        return true;
    }

    /**
     * ???URL???????<br>
     * ??????????errors???
     * false??
     *
     * <p>??HTTP?FTP????
     * URL???????
     * </p>
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;date&quot;
     *      depends=&quot;url&quot;&gt;
     *    &lt;arg key=&quot;label.date&quot; position=&quot;0&quot;/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;allowallschemes&lt;/var-name&gt;
     *      &lt;var-value&gt;false&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;allow2slashes&lt;/var-name&gt;
     *      &lt;var-value&gt;true&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;nofragments&lt;/var-name&gt;
     *      &lt;var-value&gt;false&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;schemes&lt;/var-name&gt;
     *      &lt;var-value&gt;http,ftp&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> allowallschemes </td>
     *   <td>trueor false</td>
     *   <td>false</td>
     *   <td>??????false</td>
     *  </tr>
     *  <tr>
     *   <td> allow2slashes </td>
     *   <td>trueor false</td>
     *   <td>false</td>
     *   <td>????false</td>
     *  </tr>
     *  <tr>
     *   <td> nofragments </td>
     *   <td>trueor false</td>
     *   <td>false</td>
     *   <td>URL???false</td>
     *  </tr>
     *  <tr>
     *   <td> schemes </td>
     *   <td></td>
     *   <td>false</td>
     *   <td>??????
     *       ?http, https, ftp</td>
     *  </tr>
     * </table>
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     */
    public boolean validateUrl(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // ???
        boolean allowallschemes = "true".equals(field.getVarValue("allowallschemes"));
        boolean allow2slashes = "true".equals(field.getVarValue("allow2slashes"));
        boolean nofragments = "true".equals(field.getVarValue("nofragments"));
        String schemesVar = allowallschemes ? null : field.getVarValue("schemes");

        // 
        if (!ValidationUtil.isUrl(value, allowallschemes, allow2slashes, nofragments, schemesVar)) {
            rejectValue(errors, field, va, bean);
            return false;
        }
        return true;
    }

    /**
     * ???????????
     * ??
     * ??????????errors???
     * false??
     *
     * <p>????5?10??????? true
     * ?????
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;stringField&quot;
     *      depends=&quot;byteRange&quot;&gt;
     *    &lt;arg key=&quot;sample.stringField&quot; position="0"/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;maxByteLength&lt;/var-name&gt;
     *      &lt;var-value&gt;10&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;minByteLength&lt;/var-name&gt;
     *      &lt;var-value&gt;5&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;encoding&lt;/var-name&gt;
     *      &lt;var-value&gt;Windows-31J&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> maxByteLength </td>
     *   <td>?</td>
     *   <td>false</td>
     *   <td>??????
     *        ???<code>int</code>???</td>
     *  </tr>
     *  <tr>
     *   <td> minByteLength </td>
     *   <td>??</td>
     *   <td>false</td>
     *   <td>???????
     *        ???0??</td>
     *  </tr>
     *  <tr>
     *   <td> encoding </td>
     *   <td></td>
     *   <td>false</td>
     *   <td>??????
     *   ?????VM???</td>
     *  </tr>
     * </table>
     *
     * @param bean ?
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     * @throws ValidatorException validation??????
     * ?
     */
    public boolean validateByteRange(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        String encoding = field.getVarValue("encoding");

        // ??
        int min = 0;
        String minStr = field.getVarValue("minByteLength");
        if (!GenericValidator.isBlankOrNull(minStr)) {
            try {
                min = Integer.parseInt(minStr);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- minByteLength is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }

        // ?
        int max = Integer.MAX_VALUE;
        String maxStr = field.getVarValue("maxByteLength");
        if (!GenericValidator.isBlankOrNull(maxStr)) {
            try {
                max = Integer.parseInt(maxStr);
            } catch (NumberFormatException e) {
                String message = "Mistake on validation definition file. " + "- maxByteLength is not number. "
                        + "You'll have to check it over. ";
                log.error(message, e);
                throw new ValidatorException(message);
            }
        }

        // 
        try {
            if (!ValidationUtil.isByteInRange(value, encoding, min, max)) {
                rejectValue(errors, field, va, bean);
                return false;
            }
        } catch (IllegalArgumentException e) {
            log.error("encoding[" + encoding + "] is not supported.");
            throw new ValidatorException("encoding[" + encoding + "] is not supported.");
        }
        return true;
    }

    /**
     * ???????????
     * ??????????errors???
     * false??
     *
     * <p>???2000/01/01?2010/12/31????????
     * ???
     *
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;sample&quot;&gt;
     *  
     *  &lt;field property=&quot;date&quot;
     *      depends=&quot;dateRange&quot;&gt;
     *    &lt;arg key=&quot;date&quot; position=&quot;0&quot;/&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;startDate&lt;/var-name&gt;
     *      &lt;var-value&gt;2000/01/01&lt;/var-value&gt;
     *    &lt;/var&gt;
     *    &lt;var&gt;
     *      &lt;var-name&gt;endDate&lt;/var-name&gt;
     *      &lt;var-value&gt;2010/12/31&lt;/var-value&gt;
     *    &lt;/var&gt;
     *  &lt;/field&gt;
     *  
     * &lt;/form&gt;
     * </pre></code>
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> startDate </td>
     *   <td></td>
     *   <td>false</td>
     *   <td>????
     *   ????????</td>
     *  </tr>
     *  <tr>
     *   <td> endDate </td>
     *   <td></td>
     *   <td>false</td>
     *   <td>????
     *   ????????</td>
     *  </tr>
     *  <tr>
     *   <td> datePattern </td>
     *   <td></td>
     *   <td>false</td>
     *   <td>????????
     *   ??????yyyy/MM/dd???2001/1/1?????
     *   datePattern?datePatternStrict???????
     *   datePattern????
     *   </td>
     *  </tr>
     *  <tr>
     *   <td> datePatternStrict </td>
     *   <td></td>
     *   <td>false</td>
     *   <td>?????
     *   ???????????
     *   ??????yyyy/MM/dd???2001/1/1???
     *   datePattern?datePatternStrict???????
     *   datePattern????
     *   </td>
     *  </tr>
        
     * </table>
     *
     * @param bean ?
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? true
     * @throws ValidatorException datePattern???datePatternStrict???
     * ?????startDate???endDate????????
     * ???
     */
    public boolean validateDateRange(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        // 
        String value = extractValue(bean, field);
        if (StringUtils.isEmpty(value)) {
            return true;
        }

        // 
        String datePattern = field.getVarValue("datePattern");
        String datePatternStrict = field.getVarValue("datePatternStrict");

        // ?
        String startDateStr = field.getVarValue("startDate");
        String endDateStr = field.getVarValue("endDate");

        // 
        try {
            if (!ValidationUtil.isDateInRange(value, startDateStr, endDateStr, datePattern, datePatternStrict)) {
                rejectValue(errors, field, va, bean);
                return false;
            }
        } catch (IllegalArgumentException e) {
            log.error(e.getMessage());
            throw new ValidatorException(e.getMessage());
        }
        return true;
    }

    /**
     * ????????
     * ??????????errors???
     * false??
     *
     * <p>??????????
     * ?????????validation.xml?
     * ??depends????Array???????
     * depends="requiredArray" "required" ?
     *
     * @param bean ?JavaBean
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ????????? true
     * @throws ValidatorException validation??????
     * ???bean?null?????
     */
    public boolean validateArraysIndex(Object bean, ValidatorAction va, Field field, ValidationErrors errors)
            throws ValidatorException {
        if (bean == null) {
            log.error("validation target bean is null.");
            throw new ValidatorException("validation target bean is null.");
        }

        @SuppressWarnings("rawtypes")
        Class[] paramClass = null; // ??
        Method method = null; // 
        try {
            paramClass = getParamClass(va);
            if (paramClass == null || paramClass.length == 0) {
                String message = "Mistake on validation rule file. " + "- Can not get argument class. "
                        + "You'll have to check it over. ";
                log.error(message);
                throw new ValidatorException(message);
            }

            method = getMethod(va, paramClass);
            if (method == null) {
                String message = "Mistake on validation rule file. " + "- Can not get validateMethod. "
                        + "You'll have to check it over. ";
                log.error(message);
                throw new ValidatorException(message);
            }
        } catch (RuntimeException e) {
            log.error(e.getMessage(), e);
            throw new ValidatorException(e.getMessage());
        }

        try {
            // ???????????
            Object[] argParams = new Object[paramClass.length];
            argParams[0] = bean;
            argParams[1] = va;
            argParams[3] = errors;

            // ?????
            IndexedBeanWrapper bw = getIndexedBeanWrapper(bean);
            Map<String, Object> propertyMap = bw.getIndexedPropertyValues(field.getKey());

            boolean isValid = true; // 

            for (String key : propertyMap.keySet()) {
                // ??????????
                Field indexedField = (Field) field.clone();
                indexedField.setKey(key);
                indexedField.setProperty(key);

                argParams[2] = indexedField; // 

                // ????
                boolean bool = (Boolean) method.invoke(this, argParams);
                if (!bool) {
                    isValid = false;
                }
            }
            return isValid;
        } catch (InvocationTargetException e) {
            Throwable t = e.getTargetException();
            if (t instanceof ValidatorException) {
                throw (ValidatorException) t;
            }
            log.error(t.getMessage(), t);
            throw new ValidatorException(t.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ValidatorException(e.getMessage());
        }
    }

    /**
     * IndexedBeanWrapper??
     * @param bean ?Bean
     * @return IndexedBeanWrapper?
     */
    protected IndexedBeanWrapper getIndexedBeanWrapper(Object bean) {
        return new JXPathIndexedBeanWrapperImpl(bean);
    }

    /**
     * ?????
     *
     * @param va Validator????ValidatorAction
     * @return ?
     */
    @SuppressWarnings("rawtypes")
    protected Class[] getParamClass(ValidatorAction va) {

        StringTokenizer st = new StringTokenizer(va.getMethodParams(), ",");
        Class[] paramClass = new Class[st.countTokens()];

        for (int i = 0; st.hasMoreTokens(); i++) {
            try {
                String key = st.nextToken().trim();
                paramClass[i] = ClassUtils.getClass(key);
            } catch (ClassNotFoundException e) {
                return null;
            }
        }
        return paramClass;
    }

    /**
     * ??????
     *
     * @param va ValidatorAction
     * @param paramClass ?
     * @return 
     */
    protected Method getMethod(ValidatorAction va, @SuppressWarnings("rawtypes") Class[] paramClass) {

        String methodNameSource = va.getName();
        if (methodNameSource == null || "".equals(methodNameSource)) {
            // ???null???????null?
            return null;
        }

        // name?"Array"??????
        // xxxxArrayvalidateXxxx
        char[] chars = methodNameSource.toCharArray();
        chars[0] = Character.toUpperCase(chars[0]);
        String validate = "validate" + new String(chars);
        String methodName = validate.substring(0, validate.length() - "Array".length());

        Method method = null;
        try {
            method = FieldChecks.class.getMethod(methodName, paramClass);
        } catch (NoSuchMethodException e) {
            return null;
        }
        return method;
    }

    /**
     * ???
     *
     * ?????{@link MultiFieldValidator} ???<br>
     * ??? <code>validation.xml</code> ??<br>
     * ???????????
     * ????
     * ???????????
     * ? <code>validation.xml</code> ?????<br>
     * value???value1??
     * value2????????????
     * ?
     * <h5>{@link MultiFieldValidator} ?</h5>
     * <code><pre>
     * public boolean validate(Object value, Object[] depends) {
     *     int value0 = Integer.parseInt(value);
     *     int value1 = Integer.parseInt(depends[0]);
     *     int value2 = Integer.parseInt(depends[1]);
     *     return (value1 <= value0 && value2 >= value0);
     * }
     * </pre></code>
     * <h5>validation.xml?</h5>
     * <code><pre>
     * &lt;form name=&quot;/validateMultiField&quot;&gt;
     *   &lt;field property=&quot;value&quot; depends=&quot;multiField&quot;&gt;
     *     &lt;msg key=&quot;errors.multiField&quot;
     *             name=&quot;multiField&quot;/&gt;
     *     &lt;arg key=&quot;label.value&quot; position=&quot;0&quot; /&gt;
     *     &lt;arg key=&quot;label.value1&quot; position=&quot;1&quot; /&gt;
     *     &lt;arg key=&quot;label.value2&quot; position=&quot;2&quot; /&gt;
     *     &lt;var&gt;
     *       &lt;var-name&gt;fields&lt;/var-name&gt;
     *       &lt;var-value&gt;value1,value2&lt;/var-value&gt;
     *     &lt;/var&gt;
     *     &lt;var&gt;
     *       &lt;var-name&gt;multiFieldValidator&lt;/var-name&gt;
     *       &lt;var-value&gt;sample.SampleMultiFieldValidator&lt;/var-value&gt;
     *     &lt;/var&gt;
     *   &lt;/field&gt;
     * &lt;/form&gt;
     * </pre></code>
     * <h5>?</h5>
     * <code>
     * errors.multiField={0}?{1}?{2}?????????
     * </code>
     *
     * <h5>validation.xml???&lt;var&gt;?</h5>
     * <table border="1">
     *  <tr>
     *   <td><center><b><code>var-name</code></b></center></td>
     *   <td><center><b><code>var-value</code></b></center></td>
     *   <td><center><b></b></center></td>
     *   <td><center><b>?</b></center></td>
     *  </tr>
     *  <tr>
     *   <td> fields </td>
     *   <td>??????</td>
     *   <td>false</td>
     *   <td>???????
     *   ?</td>
     *  </tr>
     *  <tr>
     *   <td> multiFieldValidator </td>
     *   <td>{@link MultiFieldValidator} ??</td>
     *   <td>true</td>
     *   <td>??? {@link MultiFieldValidator}
     *   ??</td>
     *  </tr>
     * </table>
     *
     * @param bean ?
     * @param va Validator????ValidatorAction
     * @param field 
     * @param errors 
     * @return ???? <code>true</code>
     */
    public boolean validateMultiField(Object bean, ValidatorAction va, Field field, ValidationErrors errors) {

        // bean?null????true??
        if (bean == null) {
            log.error("bean is null.");
            return true;
        }

        // ??
        Object value = null;
        if (bean instanceof String) {
            value = bean;
        } else {
            try {
                value = PropertyUtils.getProperty(bean, field.getProperty());
            } catch (IllegalAccessException e) {
                log.error(e.getMessage(), e);
            } catch (InvocationTargetException e) {
                log.error(e.getMessage(), e);
            } catch (NoSuchMethodException e) {
                log.error(e.getMessage(), e);
            }
        }
        // ????????
        // ?null?????????

        // MultiFieldValidator???
        String multiFieldValidatorClass = field.getVarValue("multiFieldValidator");

        if (multiFieldValidatorClass == null || "".equals(multiFieldValidatorClass)) {
            log.error("var value[multiFieldValidator] is required.");
            throw new IllegalArgumentException("var value[multiFieldValidator] is required.");
        }

        MultiFieldValidator mfv = null;
        try {
            mfv = (MultiFieldValidator) ClassUtil.create(multiFieldValidatorClass);
        } catch (ClassLoadException e) {
            log.error("var value[multiFieldValidator] is invalid.", e);
            throw new IllegalArgumentException("var value[multiFieldValidator] is invalid.", e);
        } catch (ClassCastException e) {
            log.error("var value[multiFieldValidator] is invalid.", e);
            throw new IllegalArgumentException("var value[multiFieldValidator] is invalid.", e);
        }

        // ????
        String fields = field.getVarValue("fields");
        List<Object> valueList = new ArrayList<Object>();
        if (fields != null) {
            StringTokenizer st = new StringTokenizer(fields, ",");
            while (st.hasMoreTokens()) {
                String f = st.nextToken();
                f = f.trim();
                try {
                    valueList.add(PropertyUtils.getProperty(bean, f));
                } catch (IllegalAccessException e) {
                    log.error(e.getMessage(), e);
                } catch (InvocationTargetException e) {
                    log.error(e.getMessage(), e);
                } catch (NoSuchMethodException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("dependent fields:" + valueList);
        }

        Object[] values = new Object[valueList.size()];

        valueList.toArray(values);

        boolean result = mfv.validate(value, values);

        if (!result) {
            rejectValue(errors, field, va, bean);
            return false;
        }

        return true;
    }

    /**
     * ???bean?Null???Null?
     * bean?String???bean?
     * bean?Number?Boolean?Character???bean.toString()?
     * ?????bean?<code>Field</code>???
     * <code>ValidatorUtils</code>?????
     *
     * @param bean ?
     * @param field <code>Field</code>
     * @return 
     * @see ValidatorUtils#getValueAsString(Object, String)
     */
    protected String extractValue(Object bean, Field field) {
        String value = null;

        if (bean == null) {
            return null;
        } else if (bean instanceof String) {
            value = (String) bean;
        } else if (bean instanceof Number || bean instanceof Boolean || bean instanceof Character) {
            value = bean.toString();
        } else {
            value = ValidatorUtils.getValueAsString(bean, field.getProperty());
        }
        return value;
    }

    /**
     * ????????
     * TERASOLUNA?????
     *
     * @param errors 
     * @param va Validator????ValidatorAction
     * @param field 
     * @param bean ???JavaBean
     */
    protected void rejectValue(ValidationErrors errors, Field field, ValidatorAction va, Object bean) {
        errors.addError(bean, field, va);
    }
}