jsf转换器getAsString()始终将null作为参数

时间:2014-08-07 15:54:50

标签: jsf-2 null converter

我想创建自己的日期转换器。我的输入字段为f:converter id =" MyConverter"。当我输入"今天"我今天要显示的价值日期。方法getAsObject运行良好。我有价值"今天"从输入字段并返回新的LocalDate(),但方法getAsObject()始终为null作为值。我该怎么做才能解决它?

    @FacesConverter(forClass = Date.class, value = "MyConverter")
public class MyConverter implements Converter {


    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException {

        if (value == null) {
            return null;
        }

        if (value.equals("today")) {
            return new LocalDate();
        }
       //do something else

    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException {
    // value is always null!
    if (value instanceof LocalDate) {
            LocalDate date = (LocalDate) value;
            return date.toString();
        } else {
            return "";
        }
    }

编辑:

jsf标签(它有点复杂)它实际上是2个日期输入字段(日期间隔组件),我想在其上使用MyDateConverter:

    <cc:interface componentType="DateIntervalComponent">
        <cc:attribute name="value" required="true" />
        <cc:attribute name="placeholder" />
        <cc:attribute name="labelFromDate" default="From Date" />
        <cc:attribute name="labelToDate" default="To Date" />
    </cc:interface>

<cc:implementation>
        <div id="#{cc.userId}">
            <b:input id="fromDate" binding="#{cc.FromDateComponent}"
                label="#{cc.attrs.labelFromDate}">
                <f:converter converterId="MyConverter" />
                <f:ajax render="#{cc.userId}" />
            </b:input>

            <b:input id="toDate" binding="#{cc.ToDateComponent}"
                label="#{cc.attrs.labelToDate}">
                <f:converter converterId="MyConverter" />
                <f:ajax render="#{cc.userId}" />
            </b:input>

        </div>

</cc:implementation>


@FacesComponent("DateIntervalComponent")
public class DateIntervalComponent extends UIInput implements NamingContainer {

    private UIInput fromDateComponent;

    private UIInput toDateComponent;

    public DateIntervalComponent() {
        setRendererType(null);
    }

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

    @Override
    public DateInterval getValue() {
        return (DateInterval) super.getValue();
    }

    @Override
    public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
        super.processEvent(event);
    }

    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        if (fromDateComponent != null && toDateComponent != null) {
            DateInterval value = getValue();
            if (!fromDateComponent.isLocalValueSet()) {
                fromDateComponent.setValue(value != null ? value.getStart() : null);
            }
            if (!toDateComponent.isLocalValueSet()) {
                toDateComponent.setValue(value != null ? value.getEnd() : null);
            }
        }

        super.encodeBegin(context);
    }

    @Override
    public DateInterval getSubmittedValue() {
        Object startValue = fromDateComponent.getValue();
        Object endValue = toDateComponent.getValue();

        return new DateInterval((Date) startValue, (Date) endValue);
    }

    @Override
    public void validate(FacesContext context) {
        super.validate(context);

        if (!isValid()) {
            fromDateComponent.setValid(false);
            toDateComponent.setValid(false);
            return;
        }
    }

    @Override
    public void resetValue() {
        super.resetValue();
        fromDateComponent.resetValue();
        toDateComponent.resetValue();
    }


    public UIInput getFromDateComponent() {
        return fromDateComponent;
    }

    public UIInput getToDateComponent() {
        return toDateComponent;
    }

    public void setToDateComponent(UIInput toDateComponent) {
        this.toDateComponent = toDateComponent;
    }


    public void setFromDateComponent(UIInput fromDateComponent) {
        this.fromDateComponent = fromDateComponent;
    }
}

问候

1 个答案:

答案 0 :(得分:1)

只要FacesComponent本身是STATELESS,您就需要跟踪属性的状态。

我使用以下策略来保持FacesComponent attibutes的状态

首先,基于UINamingContainer创建一个泛型类(如果这是你的组件类型)。

public class MyUINamingContainer extends UINamingContainer {

    @SuppressWarnings("unchecked")
    /**
     * Searches for an attribute and return it.
     */
    protected <T> T getAttribute(String attName) {
        return (T) getStateHelper().eval(attName);
    }

    @SuppressWarnings("unchecked")
    /**
     * Evaluate an attribute and return it if found.
     */
    protected <T> T getAttribute(String localName, String attName) {
        return (T) getStateHelper().eval(localName, getAttributes().get(attName));
    }

    /**
     * Refresh the attributes state
     * 
     * @param <T>
     * @param attName attribute's name. This name will identify the attribute into the map. 
        It must be different from the name used to the attribute on the view, otherwise
        it will cause a infinite loop.
     * @param value attribute's value.
    */
    protected <T> void setAttribute(String attName, T value) {
        getStateHelper().put(attName, value);
    }
}

然后,让我的FacesComponent类继承它,这样它就会知道有状态的getter和setter:

@FacesComponent("myComponent")
public class MyComponent extends MyUINamingContainer {

    public SomeType getMyAttributeOnStateMap() {
        return getAttribute("myAttributeOnStateMap","myAttribute");
    }

    public void setMyAttributeOnStateMap(SomeType myAttribute) {
        setAttribute("myAttributeOnStateMap", myAttribute);
    }
}

进入组件xhtml代码:

<cc:interface componentType="myComponent">
    <cc:attribute name="myAttribute"/>
</cc:interface>

<cc:implementation>
    <h:input value="#{cc.myAttributeOnStateMap}" />
<cc:implementation>

PS。:请注意,该属性在地图中具有不同的名称。这是因为它会卡在一个循环中,你使用map属性和视图属性的相同名称。方法getAttribute(String,String)总是查找相同的属性,从不找到任何东西,导致溢出。

PS2:请注意,用作h:input值的名称是用于将其存储到地图中的名称。