代码之家  ›  专栏  ›  技术社区  ›  Jonathan S. Fisher

JSF操作顺序,转换器应该在验证器之前应用吗?

  •  0
  • Jonathan S. Fisher  · 技术社区  · 5 年前

    <o:importConstants
        type="com.xxx.enums.UsState"
        var="UsState" />
    <b:selectOneMenu
        id="homeStateSelectOneMenu"
        value="#{contactPage.contact.homeState}"
        label="Home State"
        converter="DisplayableTextConverter">
        <f:selectItem
            id="selectOneUsStateSelectItem"
            itemLabel="Select One"
            noSelectionOption="true"
            itemDisabled="true" />
        <f:selectItems
            id="usStateSelectItems"
            value="#{UsState}" />
    </b:selectOneMenu>
    

    模型对象有以下字段:

    @Enumerated(EnumType.STRING)
    @Column(name = "home_state")
    @NotNull //LYNCHPIN
    private UsState homeState;
    

    转换器:

    @ApplicationScoped
    @FacesConverter(value = "DisplayableTextConverter", managed = true)
    public class DisplayableTextConverter implements Converter<DisplayableText> {
        public static final String STATE_KEY = "DisplayableTextConverter.forClass";
    
        @SuppressWarnings("unchecked")
        @Override
        public DisplayableText getAsObject(final FacesContext context, final UIComponent component, String text) {
            text = trimToNull(text);
            if (text != null) {
                final String className = (String) component.getTransientStateHelper().getTransient(STATE_KEY);
                try {
                    return DisplayableText.parseEnum(text, (Class<DisplayableText>) Class.forName(className));
                } catch (final ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
            } else {
                return null;
            }
        }
    
        @Override
        public String getAsString(final FacesContext context, final UIComponent component, final DisplayableText displayableText) {
            if (displayableText != null) {
                component.getTransientStateHelper().putTransient(STATE_KEY, displayableText.getClass().getName());
                return displayableText.getDisplayText();
            } else {
                return null;
            }
        }
    }
    

    public enum UsState implements DisplayableText {
        AL("Alabama"), AK("Alaska"), AZ("Arizona"), AR("Arkansas"), ....
    
        public final String displayText;
    
        @Override
        public String getDisplayText() {
            return displayText;
        }
    
        UsState(String specificDisplayValue) {
            displayText = specificDisplayValue;
        }
    }
    

    有趣的是如果我们把 @NotNull ,表单提交,如果我们添加它,提交失败。在堆栈跟踪中,当 在某些情况下,验证程序似乎在转换器之前被调用。为什么会这样?

    @不为空

    java.lang.IllegalArgumentException: Arkansas is not an instance of class com.xxx.UsState
        at org.apache.bval.jsr.job.ValidateProperty.<init>(ValidateProperty.java:515)
        at org.apache.bval.jsr.job.ValidationJobFactory.validateValue(ValidationJobFactory.java:76)
        at org.apache.bval.jsr.ValidatorImpl.validateValue(ValidatorImpl.java:65)
        at org.apache.bval.jsr.CascadingPropertyValidator.validateValue(CascadingPropertyValidator.java:99)
        at javax.faces.validator.BeanValidator.validate(BeanValidator.java:218)
        at javax.faces.component._ComponentUtils.callValidators(_ComponentUtils.java:291)
        at javax.faces.component.UIInput.validateValue(UIInput.java:489)
        at net.bootsfaces.component.selectOneMenu.SelectOneMenu.validateValue(SelectOneMenu.java:118)
        at net.bootsfaces.component.selectOneMenu.SelectOneMenuRenderer.decode(SelectOneMenuRenderer.java:96)
        at javax.faces.component.UIComponentBase.decode(UIComponentBase.java:479)
        at javax.faces.component.UIInput.decode(UIInput.java:371)
        at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1408)
        at javax.faces.component.UIInput.processDecodes(UIInput.java:207)
        at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1402)
        at javax.faces.component.UIForm.processDecodes(UIForm.java:154)
        at org.apache.myfaces.context.servlet.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:775)
    

    这里没有 @不为空 DisplayableTextConverter ):

        at com.xxx.jsf.converter.DisplayableTextConverter.getAsObject(DisplayableTextConverter.java:21)
        at com.xxx.jsf.converter.DisplayableTextConverter.getAsObject(DisplayableTextConverter.java:1)
        at org.apache.myfaces.cdi.converter.FacesConverterCDIWrapper.getAsObject(FacesConverterCDIWrapper.java:63)
        at net.bootsfaces.render.CoreRenderer.getConvertedValue(CoreRenderer.java:532)
        at javax.faces.component.UIInput.getConvertedValue(UIInput.java:789)
        at javax.faces.component.UIInput.validate(UIInput.java:708)
        at javax.faces.component.UIInput.processValidators(UIInput.java:293)
        at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1458)
        at javax.faces.component.UIForm.processValidators(UIForm.java:210)
        at org.apache.myfaces.context.servlet.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:779)
    

    谢谢!它在ApacheTomee8.0.6上运行,但在MyFaces2.3.8和BootsFaces1.5.0上运行

    0 回复  |  直到 5 年前
    推荐文章