【问题标题】:Can JSF converter work with objects of different types which implements the same interface, is it possible?JSF 转换器可以与实现相同接口的不同类型的对象一起使用,这可能吗?
【发布时间】:2015-01-05 17:25:42
【问题描述】:

我有不同的对象,它们都实现了相同的接口。所有这些对象都需要由<p:selectCheckboxMenu/> 选择。这些对象的默认值和选定值放在同一个Map<?,?>中,很少有这样的Maps在另一个Map中组合在一起。听起来很复杂,但请看下面的代码,一切都会清楚。

当我选择一个对象时,转换器从 MyBean(CDI bean)中获取所有对象的列表,通过 uuid 所需对象查找并返回它,而不抛出任何异常。当我尝试使用选定的对象时,问题就开始了。比如里面的这行代码: 来自MyBeanonObjectChange()方法:

List<AllObjects> objects= objectContainer.getControllers().get("Object 1").get("selected");

抛出异常:

 java.lang.ClassCastException: [Ljava.lang.Object; incompatible with java.util.List

确实,当我将鼠标悬停在 objectContainer 上时,我看到它包含 selected=[Ljava.lang.Object;@dba1b6e7} 类型的对象但是当我在 Eclipse 的表达式面板中评估同一行代码时,我得到了所需的值:MyObject1@d8f0f5f8

我一般不明白是否可以做我正在做的事情,即&lt;p:selectCheckboxMenu/&gt; 可以选择几个具有相同界面的不同对象。如果是的话,为什么我会有这个铸造问题?我的同事说这可能是我的converter 的问题,我倾向于同意她的观点,但不知道它是否正确,如果是,如何解决。

更新:看起来问题不在Converter 内部,但由于我通过Collection 动态收集选定值,作为&lt;ui:param/&gt; 的值。我将其传递为List&lt;AllObjects&gt;,然后将其返回为Object。然后我可以将其转换为Object[],然后使用自省将其中的每个对象转换为适当的对象,并且它可以工作。但是为什么它会改变初始对象呢?它不应该这样做。

提前谢谢你和我的代码:

这是一个界面:

public interfaces AllObjects{
    public String getName();
}

有多个对象,MyObjectMyObject1MyObject2,它们实现了上面的接口:

public MyObject implements AllObjects{
...
}

这是我的 bean 以及我的对象是如何初始化的:

public MyBean {

    Map<String, Map<String,List<AllObjects>>> objectContainer = new LinkedHashMap<String, Map<String,List<AllObjects>>>();

    public void init(){

        Map<String,List<AllObjects>> nameValuesPairs1 = new LinkedHashMap<String,List<AllObjects>>();
        List<AllObjects> allSelectedObjects1 = new ArrayList<AllObjects>();
        List<AllObjects> allDefaultObjects1 = new ArrayList<AllObjects>();
        nameValuesPairs.put("default",allDefaultObjects1);
        nameValuesPairs.put("selected",allSelectedObjects1);

        Map<String,List<AllObjects>> nameValuesPairs2 = new LinkedHashMap<String,List<AllObjects>>();
        List<AllObjects> allSelectedObjects2 = new ArrayList<AllObjects>();
        List<AllObjects> allDefaultObjects2 = new ArrayList<AllObjects>();
        nameValuesPairs.put("default",allDefaultObjects2);
        nameValuesPairs.put("selected",allSelectedObjects2);

        objectContainer.put("Object 1", nameValuesPairs1);
        objectContainer.put("Object 2", nameValuesPairs2);
    }
    public void onObjectChange(){
        ...
      List<AllObjects> objects= objectContainer .getControllers().get("Object 1").get("selected"); //throws exception
        ...
    }
}

我的 *.xhtml 页面:

<h:panelGroup id="object_panel">

        <ui:repeat id="objects_id" var="object" value="#{myBean.objectContainer.entrySet().toArray()}">

             <p:selectCheckboxMenu 
                            value="#{object.value['selected']}" label="#{object.key}"
                            converter="#{myObjectConverter}" 
                              filter="true" 
                              filterMatchMode="startsWith" 
                              panelStyle="width:250px">
                     <f:selectItems value="#{object.value['default']}" var="value" itemValue="#{value}" itemLabel="#{value.name}" />
                     <p:ajax  event="change" process="@this @parent" listener="#{myBean.onObjectChange}"/>
             </p:selectCheckboxMenu>
        </ui:repeat>

        </h:panelGroup>

和转换器:

public class ChartParameterConverter implements Converter, Serializable  {

        @Inject
        private MyBean myBean;

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

            AllObjects result = null;
            ...
            //here to result assigned MyObject1 or MyObject2 type depends on condition and it being returned
            ...
            return result;
        }

        ...
    }

【问题讨论】:

    标签: jsf jsf-2


    【解决方案1】:

    好的,看起来 &lt;ui:repeat&gt;&lt;p:selectCheckboxMenu&gt; 不适用于我使用的 DataModelMap&lt;String,Map&lt;String,List&lt;MyObject&gt;&gt;&gt;。我已通过以下方式更改了我的 DataModel

    public ObjectContainer{
         private String name;
         private List<MyObject> defaultObjects;
         private List<MyObject> selectedObbjects;
    }
    

    并将其作为List&lt;ObjectContainer&gt; 传递给&lt;ui:param&gt;。所以我的 *.xhtml 页面如下所示:

             <p:selectCheckboxMenu 
                            value="#{object.selectedObjects}" label="#{object.name}"
                            converter="#{myObjectConverter}" 
                              filter="true" 
                              filterMatchMode="startsWith" 
                              panelStyle="width:250px">
                     <f:selectItems value="#{object.defaultObjects}" var="value" itemValue="#{value}" itemLabel="#{value.name}" />
                     <p:ajax  event="change" process="@this @parent" listener="#{myBean.onObjectChange}"/>
             </p:selectCheckboxMenu>
        </ui:repeat>
    

    现在一切正常。 我扔掉了我的自定义转换器并使用来自Omnifaces's librarySelectItemsConverter。强烈推荐更改,代码变得更加简单易读。

    【讨论】:

      【解决方案2】:

      你可以为每个对象做一个唯一的元组,元组必须转换为唯一的字符串。你可以在一个数组中拥有可能的值。

      static Map<String,Object> uniques = new LinkedHashMap<>();
      static{
       //you could save the possible values in a Singleton Bean
       uniques.put(key,value)...
      }
      

      在您的转换器中

      getAsString -> Return a Key from Value
      getAsObject -> Return a Value by Key 
      

      【讨论】:

      • 抱歉,我不明白它对我有什么帮助?我在更新中写道,它改变了存储值的集合,而不是我收到 Array 的 List。
      • 你的值它应该有获取你的集合值的方法。你必须有一个键字符串传递给你的 html,你的 html 传递键。你从键中检索值。然后..您必须考虑如何使用值或键获取数组(变异或非)..这是转换器的方式。
      • 你的值可以是一个类来获取变异值。类 ArrayMutateContainer 具有属性 String getKey() 返回 uniqueString,集合 getMutateValues().. 存储 ArrayMutateContainer 的 Map
      猜你喜欢
      • 2013-07-13
      • 1970-01-01
      • 2021-10-05
      • 2022-01-07
      • 2013-02-02
      • 2012-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多