JSF 2.2调用包含Lambda表达式的Bean方法不触发问题
问题根因
该问题是JSF 2.2配套的默认EL 3.0实现的兼容性bug导致的。Java 8首次引入Lambda表达式,编译后会在字节码中生成invokedynamic指令,而JSR-341规范的初始实现(javax.el 3.0.0版本)对这类字节码的解析逻辑存在缺陷,当方法所属类包含Lambda相关的字节码结构时,EL解析器在匹配方法签名的阶段会抛出未捕获的运行时异常,而JSF框架默认会静默吞掉动作方法调用过程中的非应用级异常,最终表现为方法完全不触发、也没有可见报错。
调试时看到this.value.getValue(elContext)返回null且方法未执行,就是因为EL解析过程已经提前异常终止,没有走到实际调用方法的步骤,开启JSF的DEBUG级日志即可检索到被隐藏的EL方法匹配异常。
修复方案
- 方案1:升级EL表达式实现
这是最彻底的解决方法,将项目中javax.el依赖升级到3.0.1-b08及以上版本,该版本已经修复了Lambda字节码的解析兼容问题。Maven依赖配置参考:
<dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>3.0.1-b08</version> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.el</artifactId> <version>3.0.1-b08</version> </dependency>
如果应用服务器(如Tomcat、WildFly)自带了EL实现,需要调整类加载顺序,优先加载项目引入的高版本EL库,或直接升级服务器内置的EL组件版本。
- 方案2:临时兼容写法
若暂时无法升级依赖,可以将方法内的Lambda表达式替换为等价的匿名内部类实现,规避EL解析缺陷:
List<Customer> charlesWithMoreThan100Points = customers .stream() .filter(new Predicate<Customer>() { @Override public boolean test(Customer c) { return c.getPoints() > 100 && c.getName().startsWith("Charles"); } }) .collect(Collectors.toList());
内容的提问来源于stack exchange,提问作者Manuel Drieschmanns
相关产品推荐
相关产品推荐

