Wicket9发送自定义Event触发NotSerializableException异常如何解决
Wicket 9事件非序列化原生解决方案
错误根因说明
- 序列化异常:Wicket页面在请求结束后会序列化到存储介质,若事件payload被组件关联持有,会触发序列化检查,未实现
Serializable的类会抛出对应异常 IllegalArgumentException:你自定义事件中使用的LoadableDetachableModel内部Lambda持有外部实例引用,若引用对象不可序列化,LDModel序列化校验时会抛出参数为空异常
原生解决方案(两种可选,均为Wicket内置能力)
方案1:使用官方TransientPayload包装(无需修改现有事件类,推荐)
Wicket 7+内置org.apache.wicket.event.TransientPayload工具类,专门用于包装不需要序列化的事件payload,本身已实现序列化接口,内部持有的真实payload用transient修饰,序列化时自动忽略。
- 修改发送事件的代码,将自定义事件用
TransientPayload包裹:
send(component, Broadcast.EXACT, TransientPayload.of(new MyEvent(target, item, myToolbar)));
- 修改事件监听代码,先解包再判断类型:
@Override public void onEvent(IEvent<?> event) { super.onEvent(event); Object payload = event.getPayload(); if (payload instanceof TransientPayload) { Object realPayload = ((TransientPayload<?>) payload).getPayload(); if (realPayload instanceof MyEvent) { performAction((MyEvent) realPayload); } } }
方案2:给事件类加序列化标记+transient修饰临时字段
如果确定事件只会在当前请求周期内消费,不会跨请求使用,可直接修改事件类:
- 让
MyEvent实现Serializable接口 - 所有请求级临时字段(包括
AjaxRequestTarget、不需要持久化的Model)都加transient修饰,序列化时自动忽略这些字段
public class MyEvent implements Serializable { private final transient AjaxRequestTarget target; // 事件仅当前请求有效时,甚至可以直接去掉LDModel,用普通字段存储引用即可,避免LDModel序列化校验问题 private final transient MyItem item; private final transient MyToolbar myToolbar; public MyEvent(AjaxRequestTarget target, MyItem item, MyToolbar myToolbar) { this.target = target; this.item = item; this.myToolbar = myToolbar; } // getter保持不变 }
额外优化建议
你当前的使用场景是Ajax请求内发送事件,同请求内就会完成消费,事件不会被持久化,完全没必要用LoadableDetachableModel存储参数,直接存普通对象引用即可,从根源上避免LDModel的序列化校验异常。
内容的提问来源于stack exchange,提问作者miroana
相关产品推荐
相关产品推荐

