PrimeFaces按钮触发两类Jakarta Faces随机异常的排查与修复咨询
问题分析与修复方案
问题根源
这两个异常本质都是集合操作的并发不一致,与JSF请求处理阶段的组件树状态变化、集合迭代时的修改有关:
- IndexOutOfBoundsException(Jakarta Faces 2.3.14):
ComponentSupport.findChildByTagId方法访问ArrayList时,集合大小在索引访问前被修改,导致索引越界。 - ConcurrentModificationException(Jakarta Faces 2.3.17):
ComponentSupport.addAllDescendantMarkIds迭代HashMap时,集合被当前线程或其他线程修改,触发JDK集合的fast-fail机制。
具体到你的代码,触发点可能包括:
- 按钮同时使用
<p:commandButton>自带AJAX和<f:ajax>,导致双重AJAX请求处理,引发组件树状态的并发修改。 #{b.getNotizen().isEmpty()}多次调用,若getNotizen()返回非线程安全集合(如ArrayList),且该集合在请求过程中被其他代码修改,就会触发异常。- 按钮的
disabled/rendered属性依赖的b.id、b.typ在请求处理阶段被并发修改,导致组件树状态不一致。
修复方案
1. 移除冗余的<f:ajax>标签
<p:commandButton>默认启用AJAX(除非显式设置ajax="false"),添加<f:ajax>会导致重复的AJAX处理逻辑,这是触发这类异常的常见原因。修改后的按钮代码:
<p:commandButton styleClass="old" update="editnotizForm" oncomplete="PF('editnotizDialog').show()" icon="ui-icon-assignment" disabled="#{b.id le 0 || b.typ eq 'P'}" rendered="#{b.typ ne 'P'}" style="#{b.notizen.isEmpty() ? 'background-color:gray;':'background-color:green;'};width:23px;height:23px;border:none"> <f:setPropertyActionListener value="#{b}" target="#{psbBean.aktiv}" /> </p:commandButton>
注意:将
getNotizen()改为EL表达式规范的notizen,避免重复调用方法返回不同集合实例。
2. 确保集合线程安全
将b.notizen这类在组件中使用的集合,包装为线程安全实现:
- 若为List,使用
CopyOnWriteArrayList(适合读多写少场景)或Collections.synchronizedList():
private List<Notiz> notizen = new CopyOnWriteArrayList<>(); // 或者 private List<Notiz> notizen = Collections.synchronizedList(new ArrayList<>());
- 若为Map,使用
ConcurrentHashMap替代普通HashMap。
3. 避免请求阶段并发修改组件依赖数据
确保b.id、b.typ、b.notizen这些组件属性依赖的数据,在AJAX请求处理过程中不会被并发修改:
- 如有异步操作修改这些数据,需添加同步锁保护;
- 尽量将数据修改逻辑放在请求的早期阶段(如
@PostConstruct或非AJAX请求中),避免在渲染、AJAX回调阶段修改。
4. 验证PrimeFaces与Jakarta Faces版本兼容性
确保PrimeFaces版本与Jakarta Faces 2.3.17兼容,推荐使用PrimeFaces 10及以上版本(Jakarta Faces 2.3对应PrimeFaces 10+),版本不兼容可能引发底层组件树操作异常。
内容的提问来源于stack exchange,提问作者Vikanto
相关产品推荐
相关产品推荐

