如何检测验证器中的 valueChange 事件?

How to detect valueChange event in validator?

莫哈拉 2.1

我需要为 h:inputText 编写一个验证器,它仅在该输入的值发生变化时才执行一些逻辑。即

public class MyValidator implements Validator{

    public void validate(FacesContext context,
                         UIComponent component,
                         Object value) throws ValidatorException;
         if(valueChanged(UIComponent component)){ //The method checks if the value's changed
               //do some piece of logic
         }
         return;
     }
}

我深入研究了 UIInput 的排队事件并发现了这个:

validateValue(context, newValue);

// If our value is valid, store the new value, erase the
// "submitted" value, and emit a ValueChangeEvent if appropriate
if (isValid()) {
        Object previous = getValue();
        setValue(newValue);
        setSubmittedValue(null);
        if (compareValues(previous, newValue)) {
            queueEvent(new ValueChangeEvent(this, previous, newValue));
        }
    }

这段代码来自方法,由Validation阶段回调执行。我脑海中浮现的第一个想法是查询在处理请求期间触发的所有事件。 queueEvent(FacesEvent)方法实现如下:

 public void queueEvent(FacesEvent event) {

    if (event == null) {
        throw new NullPointerException();
    }
    UIComponent parent = getParent();
    if (parent == null) {
        throw new IllegalStateException();
    } else {
        parent.queueEvent(event);
    }

}

因此,每个这样的调用都将在 UIViewRoot.queueEvent(FacesEvent) 中结束,实现为:

public void queueEvent(FacesEvent event) {

    if (event == null) {
        throw new NullPointerException();
    }
    // We are a UIViewRoot, so no need to check for the ISE
    if (events == null) {
        int len = PhaseId.VALUES.size();
        List<List<FacesEvent>> events = new ArrayList<List<FacesEvent>>(len);
        for (int i = 0; i < len; i++) {
            events.add(new ArrayList<FacesEvent>(5));
        }
        this.events = events;
    }
    events.get(event.getPhaseId().getOrdinal()).add(event);
}

这意味着,所有事件实际上都存储为每个阶段的 List<List<FacesEvent>>。但是 List<List<FacesEvent>> events 是私有字段,所以无法直接访问它。

另一件事是实际验证是在 quingEvent 之前执行的,因此实施 valueChangeListener 似乎也没有用。

问题:是否有可能以自然的方式在JSF中实现这样的验证器?

你自己比价吧。在验证器中,旧值很容易通过 UIComponent 参数获得。

@Override
public void validate(FacesContext context, UIComponent component, Object submittedValue) {
    if (component instanceof EditableValueHolder) {
        Object newValue = submittedValue;
        Object oldValue = ((EditableValueHolder) component).getValue();

        if (newValue == null ? oldValue == null : newValue.equals(oldValue)) {
            return; // Not changed, so skip validation.
        }
    }

    // Do actual validation here.
}

如果您碰巧使用了 JSF 实用程序库 OmniFaces, it has a ValueChangeValidator,它就是这样做的。