"Could not deserialize object from byte[]" 在 Wicket 7 中打开多个选项卡时文件上传
"Could not deserialize object from byte[]" on File Upload when Multiple tabs open in Wicket 7
我们有一个大型 wicket 应用程序有一个烦人的错误。我们有一个带有文件上传字段的表单,在大多数情况下它工作正常。唯一失败的情况是用户打开了多个浏览器选项卡。然后我们得到以下异常(每打开一个额外的选项卡一次):
java.lang.RuntimeException: Could not deserialize object from byte[]
at org.apache.wicket.serialize.java.JavaSerializer.deserialize(JavaSerializer.java:143)
at org.apache.wicket.pageStore.AbstractPageStore.deserializePage(AbstractPageStore.java:152)
at org.apache.wicket.pageStore.AbstractCachingPageStore.getPage(AbstractCachingPageStore.java:67)
at com.sw.system4.ui.RemovablePageManagerProvider.getPage(RemovablePageManagerProvider.java:51)
at org.apache.wicket.page.PageStoreManager$SessionEntry.getPage(PageStoreManager.java:231)
at org.apache.wicket.page.PageStoreManager$PersistentRequestAdapter.getPage(PageStoreManager.java:393)
at org.apache.wicket.page.AbstractPageManager.getPage(AbstractPageManager.java:82)
at org.apache.wicket.page.PageManagerDecorator.getPage(PageManagerDecorator.java:50)
at org.apache.wicket.page.PageAccessSynchronizer.getPage(PageAccessSynchronizer.java:246)
at org.apache.wicket.DefaultMapperContext.getPageInstance(DefaultMapperContext.java:113)
at org.apache.wicket.core.request.handler.PageProvider.getStoredPage(PageProvider.java:299)
at org.apache.wicket.core.request.handler.PageProvider.isNewPageInstance(PageProvider.java:211)
at org.apache.wicket.core.request.mapper.AbstractBookmarkableMapper.checkExpiration(AbstractBookmarkableMapper.java:335)
at org.apache.wicket.core.request.mapper.AbstractBookmarkableMapper.processListener(AbstractBookmarkableMapper.java:309)
at org.apache.wicket.core.request.mapper.AbstractBookmarkableMapper.mapRequest(AbstractBookmarkableMapper.java:369)
at org.apache.wicket.request.mapper.CompoundRequestMapper.mapRequest(CompoundRequestMapper.java:147)
at org.apache.wicket.request.cycle.RequestCycle.resolveRequestHandler(RequestCycle.java:189)
at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:219)
at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:293)
at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:261)
at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:203)
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:284)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2517)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2506)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: java.io.FileNotFoundException: C:\Program Files\Apache Software Foundation\Tomcat 7.0\temp\upload_d17f019a_9bfa_48c5_bc2c_6fc0bf74d233_00004982.tmp (The system cannot find the file specified)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(Unknown Source)
at java.io.FileInputStream.(Unknown Source)
at org.apache.commons.fileupload.disk.DiskFileItem.readObject(DiskFileItem.java:684)
at sun.reflect.GeneratedMethodAccessor4472.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
... lots of read lines snipped
at java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at org.apache.wicket.serialize.java.JavaSerializer.deserialize(JavaSerializer.java:126)
FileUploadField 是一个更大页面的一部分的表单,因此用户选择一个文件并在继续之前使用 ajax 提交按钮上传它。
Form<?> uploadForm = new Form<Void>( "uploadForm" );
uploadForm.setMultiPart( true );
add( uploadForm );
IModel<List<FileUpload>> filesModel = Model.ofList( new ArrayList<>() );
uploadForm.add( new FileUploadField( "uploadField", filesModel) );
uploadForm.add( new AjaxBeforeSubmitLink( "loadLink" ) {
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit( AjaxRequestTarget target, Form<?> form ) {
List<? extends FileUpload> files = filesModel.getObject();
if ( l_files != null && !l_files.isEmpty() ) {
callEntryModel.getObject().getVendorQuoteData().getFileUploads().addAll( files );
}
target.add( getUploadedFilesLabel() );
target.add( getClearFilesLink() );
onUpdateContractQuoteData( target );
}
});
上传面板是 'breadcrumb' 样式页面的一部分,使用 BreadCrumbPanels 来自 wicket 扩展。上传部分在一个面板上,然后被面包屑中的下一个面板替换。当他们尝试做任何导致 ajax 调用的错误发生时,它就在那个面板上。
据我所知,客户端请求有某种哈希函数来定义要加载的临时文件的名称,这对于不同的选项卡是不同的?有没有其他人遇到过这个问题,我似乎无法在任何地方找到任何参考资料。
我们正在使用 Java 8/Wicket 7.10
提前致谢
您似乎在页面中保留了对 FileItem 对象的引用。
Wicket 尝试从其页面存储中反序列化该页面,在此过程中,它尝试加载一个 org.apache.commons.fileupload.disk.DiskFileItem
,它不再有支持文件。
Wicket 的 FileUploadField 有一个 transient field - a List<FileUpload>
. But since it is transient it won't be serialized at all. Later when its public List<FileUpload> getFileUploads()
is called this field will be null
and Wicket will use commons-fileupload
APIs to load it again.
对我来说,您的应用程序似乎在某处保留了对 DiskFileItem 的引用,因此它是 serialized/deserialized。
您可以使用 Wicket IObjectChecker 查找引用它的位置。请参阅 SessionChecker 和 DifferentPageChecker 以获取如何实现自定义检查器的灵感。
我们有一个大型 wicket 应用程序有一个烦人的错误。我们有一个带有文件上传字段的表单,在大多数情况下它工作正常。唯一失败的情况是用户打开了多个浏览器选项卡。然后我们得到以下异常(每打开一个额外的选项卡一次):
java.lang.RuntimeException: Could not deserialize object from byte[]
at org.apache.wicket.serialize.java.JavaSerializer.deserialize(JavaSerializer.java:143)
at org.apache.wicket.pageStore.AbstractPageStore.deserializePage(AbstractPageStore.java:152)
at org.apache.wicket.pageStore.AbstractCachingPageStore.getPage(AbstractCachingPageStore.java:67)
at com.sw.system4.ui.RemovablePageManagerProvider.getPage(RemovablePageManagerProvider.java:51)
at org.apache.wicket.page.PageStoreManager$SessionEntry.getPage(PageStoreManager.java:231)
at org.apache.wicket.page.PageStoreManager$PersistentRequestAdapter.getPage(PageStoreManager.java:393)
at org.apache.wicket.page.AbstractPageManager.getPage(AbstractPageManager.java:82)
at org.apache.wicket.page.PageManagerDecorator.getPage(PageManagerDecorator.java:50)
at org.apache.wicket.page.PageAccessSynchronizer.getPage(PageAccessSynchronizer.java:246)
at org.apache.wicket.DefaultMapperContext.getPageInstance(DefaultMapperContext.java:113)
at org.apache.wicket.core.request.handler.PageProvider.getStoredPage(PageProvider.java:299)
at org.apache.wicket.core.request.handler.PageProvider.isNewPageInstance(PageProvider.java:211)
at org.apache.wicket.core.request.mapper.AbstractBookmarkableMapper.checkExpiration(AbstractBookmarkableMapper.java:335)
at org.apache.wicket.core.request.mapper.AbstractBookmarkableMapper.processListener(AbstractBookmarkableMapper.java:309)
at org.apache.wicket.core.request.mapper.AbstractBookmarkableMapper.mapRequest(AbstractBookmarkableMapper.java:369)
at org.apache.wicket.request.mapper.CompoundRequestMapper.mapRequest(CompoundRequestMapper.java:147)
at org.apache.wicket.request.cycle.RequestCycle.resolveRequestHandler(RequestCycle.java:189)
at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:219)
at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:293)
at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:261)
at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:203)
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:284)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2517)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2506)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: java.io.FileNotFoundException: C:\Program Files\Apache Software Foundation\Tomcat 7.0\temp\upload_d17f019a_9bfa_48c5_bc2c_6fc0bf74d233_00004982.tmp (The system cannot find the file specified)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(Unknown Source)
at java.io.FileInputStream.(Unknown Source)
at org.apache.commons.fileupload.disk.DiskFileItem.readObject(DiskFileItem.java:684)
at sun.reflect.GeneratedMethodAccessor4472.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
... lots of read lines snipped
at java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at org.apache.wicket.serialize.java.JavaSerializer.deserialize(JavaSerializer.java:126)
FileUploadField 是一个更大页面的一部分的表单,因此用户选择一个文件并在继续之前使用 ajax 提交按钮上传它。
Form<?> uploadForm = new Form<Void>( "uploadForm" );
uploadForm.setMultiPart( true );
add( uploadForm );
IModel<List<FileUpload>> filesModel = Model.ofList( new ArrayList<>() );
uploadForm.add( new FileUploadField( "uploadField", filesModel) );
uploadForm.add( new AjaxBeforeSubmitLink( "loadLink" ) {
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit( AjaxRequestTarget target, Form<?> form ) {
List<? extends FileUpload> files = filesModel.getObject();
if ( l_files != null && !l_files.isEmpty() ) {
callEntryModel.getObject().getVendorQuoteData().getFileUploads().addAll( files );
}
target.add( getUploadedFilesLabel() );
target.add( getClearFilesLink() );
onUpdateContractQuoteData( target );
}
});
上传面板是 'breadcrumb' 样式页面的一部分,使用 BreadCrumbPanels 来自 wicket 扩展。上传部分在一个面板上,然后被面包屑中的下一个面板替换。当他们尝试做任何导致 ajax 调用的错误发生时,它就在那个面板上。
据我所知,客户端请求有某种哈希函数来定义要加载的临时文件的名称,这对于不同的选项卡是不同的?有没有其他人遇到过这个问题,我似乎无法在任何地方找到任何参考资料。
我们正在使用 Java 8/Wicket 7.10
提前致谢
您似乎在页面中保留了对 FileItem 对象的引用。
Wicket 尝试从其页面存储中反序列化该页面,在此过程中,它尝试加载一个 org.apache.commons.fileupload.disk.DiskFileItem
,它不再有支持文件。
Wicket 的 FileUploadField 有一个 transient field - a List<FileUpload>
. But since it is transient it won't be serialized at all. Later when its public List<FileUpload> getFileUploads()
is called this field will be null
and Wicket will use commons-fileupload
APIs to load it again.
对我来说,您的应用程序似乎在某处保留了对 DiskFileItem 的引用,因此它是 serialized/deserialized。
您可以使用 Wicket IObjectChecker 查找引用它的位置。请参阅 SessionChecker 和 DifferentPageChecker 以获取如何实现自定义检查器的灵感。