OmniFaces SelectItemsIndexConverter转换失败问题求助
你遇到的核心问题是SelectItemsIndexConverter没有按预期工作——它本该基于选项在列表中的索引完成转换,但实际提交时却在尝试把DTO的主键值转换成对象,最终导致转换报错。下面是一步步的排查和解决方法:
1. 检查托管Bean的作用域(最可能的根源)
SelectItemsIndexConverter的工作逻辑依赖渲染页面时的选项列表和提交时的列表完全一致(顺序、元素都不能变)。如果你的createBugManagedBean是@RequestScoped,提交表单时会创建全新的Bean实例,重新加载的priorities列表可能和渲染页面时的顺序不一致,甚至加载失败为空,这时候转换器用索引去取对象自然会报错。
解决方法:
把Bean改成@ViewScoped,这样同一个视图的多次请求(比如表单提交)会复用同一个Bean实例,priorities列表也会保持渲染时的状态:
import javax.faces.view.ViewScoped; import javax.inject.Named; import java.io.Serializable; @Named @ViewScoped public class CreateBugManagedBean implements Serializable { private BugPrioritiesDTO priority; private ArrayList<BugPrioritiesDTO> priorities; // 用@PostConstruct初始化列表,确保仅加载一次 @PostConstruct public void init() { // 替换成你实际加载优先级数据的逻辑 priorities = new ArrayList<>(); priorities.add(new BugPrioritiesDTO(0, "Lowest")); priorities.add(new BugPrioritiesDTO(1, "Low")); priorities.add(new BugPrioritiesDTO(2, "Medium")); // ...其他优先级选项 } // 补充getter/setter方法 public BugPrioritiesDTO getPriority() { return priority; } public void setPriority(BugPrioritiesDTO priority) { this.priority = priority; } public ArrayList<BugPrioritiesDTO> getPriorities() { return priorities; } }
2. 确保转换器正确应用
有时候会因为同名转换器覆盖或者拼写错误,导致OmniFaces的转换器没生效。可以尝试用完全限定类名指定转换器,避免冲突:
<h:selectOneMenu id="priority" value="#{createBugManagedBean.priority}" converter="org.omnifaces.converter.SelectItemsIndexConverter"> <f:selectItems value="#{createBugManagedBean.priorities}" var="priority" itemValue="#{priority}" itemLabel="#{priority.name}"/> </h:selectOneMenu>
同时确认OmniFaces的jar包已经正确放在WEB-INF/lib目录下,你的2.7.1版本和JSF 2.2/Java EE7环境是兼容的(这点无需担心,OmniFaces 2.x专门适配JSF 2.2)。
3. 备选方案:改用SelectItemsConverter(基于主键转换)
如果你的业务场景必须用RequestScoped Bean,或者更倾向于基于主键(id)而非索引转换,可以换成OmniFaces的SelectItemsConverter。这个转换器会自动通过对象的getId()方法获取唯一标识,然后从列表中匹配对应对象:
修改页面代码:
<h:selectOneMenu id="priority" value="#{createBugManagedBean.priority}" converter="omnifaces.SelectItemsConverter"> <f:selectItems value="#{createBugManagedBean.priorities}" var="priority" itemValue="#{priority}" itemLabel="#{priority.name}"/> </h:selectOneMenu>
这种方式不需要依赖视图作用域,只要提交请求时priorities列表已加载(包含所有可能的选项),且每个BugPrioritiesDTO的id是唯一的,就能正常完成转换。
最后检查点
- 确保
priorities列表在视图生命周期内(或每次请求时)没有被修改顺序、添加/删除元素 - 确认
BugPrioritiesDTO的getId()方法能正确返回主键值
内容的提问来源于stack exchange,提问作者Turkeyplague

