在<h:inputtext>标记</h:inputtext>之外的UIInputs中添加验证器

时间:2014-10-09 06:37:17

标签: jsf jsf-2 jsf-2.2 custom-component

是否可以从h:inputText标记之外的inputText字段添加验证器?

<!-- instead of this -->
    <h:inputText id="field1" value="#{backingBean.field1}">
        <f:validator validatorId="CustomValidator" />
    </h:inputText>

<!-- something like this -->
    <h:inputText id="field1" value="#{backingBean.field1}" />

    <abc:validations>
        <abc:validation for="field1" validator="CustomValidatorName" />
    </abc:validations>

abc:validation是一个非常简短的自定义组件     

    <cc:interface componentType="validation">
        <cc:attribute name="for" />
        <cc:attribute name="validator" />
    </cc:interface>

    <cc:implementation>
    </cc:implementation>

</ui:composition>

和面部组件类

package at.sozvers.ecm.webclient.frontend.component;


import java.io.Serializable;

import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponentBase;
import javax.faces.component.UINamingContainer;
import javax.faces.validator.Validator;


@FacesComponent("validation")
public class Validation extends UIComponentBase implements NamingContainer, Serializable {

    private static final long serialVersionUID = 1L;

    private String for1;
    private Validator validator;

    @Override
    public String getFamily() {
        return UINamingContainer.COMPONENT_FAMILY;
    }

    public String getFor() {
        return for1;
    }

    public void setFor(String for1) {
        this.for1 = for1;
    }

    public Validator getValidator() {
        return validator;
    }

    public void setValidator(Validator validator) {
        this.validator = validator;
    }

}                                                            

我读到了TagHandlers和ComponentHandlers,但我不知道如何开始。

1 个答案:

答案 0 :(得分:0)

我找到了解决方案

我创建了一个扩展ComponentHandlerWrapper的类,并覆盖onComponentPopulated方法,在那里我读取ViewMap并为每个必须验证的inputText id放置一个ValidatorSet。 ValidatorSet包含一个Set,我将FacesValidator名称写入。

public class ParentAddingComponentHandlerWrapper extends ComponentHandlerWrapper {

@Override
public void onComponentPopulated(FaceletContext ctx, UIComponent c, UIComponent parent) {
    super.onComponentPopulated(ctx, c, parent);
    Map<String, Object> viewMap = ctx.getFacesContext().getViewRoot().getViewMap();
    if (c instanceof Validation) { // Validation is the FacesComponent class for <abc:validation>
        TagAttribute uiInputName = getAttribute("for");
        if (null == viewMap.get(uiInputName.getValue())) {
            viewMap.put(uiInputName.getValue(), new ValidatorSet());
        }

        TagAttribute validator = getAttribute("validator"); // the validator attribute contains a FacesValidator name
        ValidatorSet validators = (ValidatorSet) viewMap.get(uiInputName.getValue());

        if (validator != null) {
            validators.addValidator(validator.getValue());
        } 
    }
}

我创建了一个CustomComponent,我在那里装饰&#34;一个inputText。我还创建了一个componentType / FacesComponent命名字段,我用@ListenerFor(systemEventClass = PreValidateEvent.class)注释了
我不得不重写我将FacesValidator添加到UIInput组件的processEvent方法

@Override
public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
    super.processEvent(event);
    Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();

    String id = getAttributeValue("id", "");
    ValidatorSet validators = (ValidatorSet) viewMap.get(id);
    if (validators != null) {
        UIComponent findComponent = findComponent(id);
        if (findComponent instanceof UIInput) {
            UIInput input = (UIInput) findComponent;
            List<Validator> inputValidators = Arrays.asList(input.getValidators());
            for (Validator validator : validators.getValidators()) {
                if (!doesUIInputContainsValidator(inputValidators, validator)) {
                    input.addValidator(validator);
                }
            }
        }
    }

}

private boolean doesUIInputContainsValidator(List<Validator> inputValidators, Validator validator) {
    for (Validator inputValidator : inputValidators) {
        if (inputValidator.getClass().isInstance(validator)) {
            return true;
        }
    }
    return false;
}