I’m here to tell that i was also having trouble with the fact that the FileDownloader is called before the button click. The below code, using button ClickListener event and setFileDownloadResource from FileDownloader worked fine for me:
How to use a button to generate a file and download it in the same action event
The solution from above did not work for me (the listener was triggered after download started).
To solve the problem I needed to create DynamicFileResource with a reflection hack (because Vaadin team decided to make the method FileResource.setSourceFile(File sourceFile) private).
@SuppressWarnings("serial")
public static class DynamicFileResource extends FileResource {
protected Callable<String> processor;
/** provide the source file using callback */
public DynamicFileResource(Callable<String> processor) {
super(new File("."));
this.processor = processor;
}
@Override
public DownloadStream getStream() {
try {
// process and set the resulted file before returning stream
String filePath = processor.call();
setSourceFile(new File(filePath));
} catch (Exception e) {
throw new IllegalStateException("Unable to generate file resource", e);
}
return super.getStream();
}
// set sourceFile (maybe Vaadin team should make the method setSourceFile(File sourceFile) public..)
public void setSourceFile(File sourceFile) {
// access private member: FileResource.sourceFile
try {
Field f = FileResource.class.getDeclaredField("sourceFile");
f.setAccessible(true); // force accessible
f.set(this, sourceFile);
} catch (Exception e) {
throw new IllegalStateException("Unable to set sourceFile", e);
}
}
}
public enum EXPORT_TYPE {
CSV, EXCEL, PDF
}
/** generated and download report */
private void attachReportExporter(Button button, final EXPORT_TYPE exportType) {
FileDownloader fileDownloader = new FileDownloader(new DynamicFileResource(() -> generateReport(exportType)));
fileDownloader.extend(button);
}
private String generateReport(EXPORT_TYPE exportType) {
// generate the report and return the path to resulted file
...
return filePath;
}
// sample usage attachExportReport()
private void createLayout() {
btnExportCsv = new Button("Export Csv");
attachReportExporter(btnExportCsv, EXPORT_TYPE.CSV);
btnExportExcel = new Button("Export Excel");
attachReportExporter(btnExportExcel, EXPORT_TYPE.EXCEL);
btnExportPdf = new Button("Export PDF");
attachReportExporter(btnExportPdf, EXPORT_TYPE.PDF);
}
Thank you very much Gill, the class DynamicFileResource solve my problem