【问题标题】:Setting a member of a domain model object derived from Map设置从 Map 派生的域模型对象的成员
【发布时间】:2015-07-22 08:26:21
【问题描述】:

我有一个域模型对象,它具有从地图派生的动态键和值:

public class MyDomainModelObject extends HashMap<String, SomeClass<?>>
{
    private String documentType;

    public MyDomainModelObject()
    {
         super();
    }

    public String getDocumentType()
    {
        return documentType;
    }

    public void setDocumentType(final String documentType)
    {
         this.documentType = documentType;
    }
}

地图中存储的值的获取和设置工作正常。 但是成员documentType的设置导致ClassCastException

documentType 是在 primefaces 数据表单元格编辑器中编辑的:

<p:dataTable ...>
    <p:column ... />
        ...
    </p:column>
    <p:column>
        <p:cellEditor>
            <f:facet name="output">
                <h:outputText value="#{curObj.getDocumentType()}" />
            </f:facet>
            <f:facet name="input">
                <p:selectOneMenu value="#{curObj.documentType}">
                    <f:selectItems value="#{someBean.determineDocumentTypes(curObj)}" var="curDocType" itemLabel="#{curDocType}"
                        itemValue="#{curDocType}" />
                </p:selectOneMenu>
            </f:facet>
        </p:cellEditor>
    </p:column>
</p:dataTable>

当我更改表内的documentType 时,我得到以下异常:

10:08:09,581 ERROR [stderr] (http-/0.0.0.0:9090-3) java.lang.ClassCastException: java.lang.String cannot be cast to SomeObject
10:08:09,581 ERROR [stderr] (http-/0.0.0.0:9090-3)  at MyDomainModel.put(MyDomainModel.java:1)
10:08:09,582 ERROR [stderr] (http-/0.0.0.0:9090-3)  at javax.el.MapELResolver.setValue(MapELResolver.java:262)
10:08:09,582 ERROR [stderr] (http-/0.0.0.0:9090-3)  at com.sun.faces.el.DemuxCompositeELResolver._setValue(DemuxCompositeELResolver.java:255)
10:08:09,582 ERROR [stderr] (http-/0.0.0.0:9090-3)  at com.sun.faces.el.DemuxCompositeELResolver.setValue(DemuxCompositeELResolver.java:281)
10:08:09,582 ERROR [stderr] (http-/0.0.0.0:9090-3)  at de.odysseus.el.tree.impl.ast.AstProperty.setValue(AstProperty.java:156)
10:08:09,582 ERROR [stderr] (http-/0.0.0.0:9090-3)  at de.odysseus.el.tree.impl.ast.AstEval.setValue(AstEval.java:87)
10:08:09,582 ERROR [stderr] (http-/0.0.0.0:9090-3)  at de.odysseus.el.TreeValueExpression.setValue(TreeValueExpression.java:146)
10:08:09,582 ERROR [stderr] (http-/0.0.0.0:9090-3)  at org.jboss.weld.el.WeldValueExpression.setValue(WeldValueExpression.java:64)
10:08:09,582 ERROR [stderr] (http-/0.0.0.0:9090-3)  at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:131)
10:08:09,583 ERROR [stderr] (http-/0.0.0.0:9090-3)  at javax.faces.component.UIInput.updateModel(UIInput.java:832)
10:08:09,583 ERROR [stderr] (http-/0.0.0.0:9090-3)  at javax.faces.component.UIInput.processUpdates(UIInput.java:749)
10:08:09,583 ERROR [stderr] (http-/0.0.0.0:9090-3)  at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1290)
10:08:09,583 ERROR [stderr] (http-/0.0.0.0:9090-3)  at org.primefaces.component.celleditor.CellEditor.processUpdates(CellEditor.java:89)
10:08:09,583 ERROR [stderr] (http-/0.0.0.0:9090-3)  at org.primefaces.component.api.UIData.process(UIData.java:379)
10:08:09,583 ERROR [stderr] (http-/0.0.0.0:9090-3)  at org.primefaces.component.api.UIData.processChildren(UIData.java:360)
10:08:09,583 ERROR [stderr] (http-/0.0.0.0:9090-3)  at org.primefaces.component.api.UIData.processPhase(UIData.java:322)
10:08:09,583 ERROR [stderr] (http-/0.0.0.0:9090-3)  at org.primefaces.component.api.UIData.processUpdates(UIData.java:308)
10:08:09,583 ERROR [stderr] (http-/0.0.0.0:9090-3)  at org.primefaces.component.datatable.DataTable.processUpdates(DataTable.java:722)
10:08:09,584 ERROR [stderr] (http-/0.0.0.0:9090-3)  at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:577)
10:08:09,584 ERROR [stderr] (http-/0.0.0.0:9090-3)  at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)

为什么用javax.el.MapELResolver来设置documentType的值? setDocumentType 方法没有被执行,而是getDocumentType。 我有点困惑。

【问题讨论】:

    标签: jsf hashmap el managed-bean


    【解决方案1】:

    为什么javax.el.MapELResolver是用来设置documentType的值的?

    这是因为基础是java.util.Map 的一个实例。基本上,EL 检查如下:

    if (curObj instanceof Map) {
        // Use MapELResolver.
    }
    else (...) {
        // ...
    }
    else {
        // Use BeanELResolver.
    }
    

    你有两个选择:

    1. 使用组合而不是继承。

      public class MyDomainModelObject {
      
          private String documentType;
          private Map<String, Foo> properties;
      
          // ...
      }
      
    2. 坚持继承并委托给它(hacky、原始类型等)。

      public String getDocumentType() {
          return (String) ((Map) this).get("documentType");
      }
      
      public void setDocumentType(final String documentType) {
          ((Map) this).put("documentType", documentType);
      }
      

      请注意,EL 不会直接使用它。它仍然会通过Map#get() 通过MapELResolver 获取它。这些方法只会被您的域代码使用。只有当你尝试循环它时它才会在那里中断。

    【讨论】:

    • 好的。谢谢。我怀疑有类似的事情,但我不知道。我将使用选项 1。
    猜你喜欢
    • 2017-07-25
    • 2021-07-25
    • 2012-09-17
    • 2017-12-02
    • 2017-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多