Hi,
In production mode, runAndShow function of the uiReportRunner interface displays PDF as raw binary/compressed data instead of readable text in the browser.
Jmix Studio Premium 2.7.5
IntelliJ IDEA 2025.3.3
Thanks in advance,

Hi,
In production mode, runAndShow function of the uiReportRunner interface displays PDF as raw binary/compressed data instead of readable text in the browser.
Jmix Studio Premium 2.7.5
IntelliJ IDEA 2025.3.3
Thanks in advance,

Hi
There is really a problem with the uiReportRunner.
If you run the actual jmx-crm from GitHub which is version 2.7.4, go to Invoices, select 1 invoice and download this invoice, you get a nice new tab with the invoice.
Now you update this project to version 2.7.5 and do the same; there is no invoice displayed and system offers a download of [GUID] file without any file extension.
One of my application with
uiReportRunner.byReportEntity(report)
.withOutputType(ReportOutputType.PDF)
.withParametersDialogShowMode(ParametersDialogShowMode.NO)
.addParam("Account", account) // Parameter alias
.addParam("dateFrom", dateFrom)
.addParam("dateTo", dateTo)
.addParam(JRParameter.REPORT_LOCALE, getLocale())
.runAndShow();
does the same; instead of opening a pdf with the defined filename, the user get a strange file download.
I think, before you distribute this version, this really should be repared.
Regards
Felix
Hi!
Thank you for reporting the issue. This is a regression, and we’re working on a fix.
Best regards,
Dmitriy
I’m also having this issue, pdf report is generated without a file ext and resulting no display.
As a temporary workaround you can do the following:
Create a FixedFileDownloader class:
public class FixedFileDownloader extends JmixFileDownloader {
private static final Logger log = LoggerFactory.getLogger(FixedFileDownloader.class);
protected void beforeClientResponseDownloadHandler(UI ui) {
String identifier = DOWNLOAD_RESOURCE_PREFIX + UUID.randomUUID();
requestHandler = (session, request, response) -> {
if (request.getPathInfo().endsWith(identifier)) {
String type = isViewDocumentRequest ? "inline" : "attachment";
response.setStatus(HttpServletResponse.SC_OK);
response.setHeader(
"Content-Disposition",
ContentDisposition.builder(type)
.filename(getFileName(session, request), StandardCharsets.UTF_8)
.build()
.toString());
response.setHeader("Cache-Control", "private, max-age=%s".formatted(cacheMaxAgeSec));
if (isViewDocumentRequest && Strings.isNotEmpty(contentType)) {
response.setContentType(contentType);
}
try {
contentWriter.andThen(this::afterWriteHandler)
.accept(response.getOutputStream());
log.debug("response {} has been sent", response);
} catch (IOException | RuntimeException e) {
if (!isViewDocumentRequest
|| fileNotFoundExceptionHandler == null
|| !fileNotFoundExceptionHandler.test(new FileNotFoundContext(e, response))) {
if (response instanceof VaadinServletResponse servletResponse) {
HttpServletResponse httpResponse = servletResponse.getHttpServletResponse();
if (httpResponse != null && httpResponse.isCommitted()) {
log.warn("Response is already committed. Status code cannot be changed.");
} else {
applyErrorHeaders(response);
}
}
// send exception further
// UI access is required to correct exception handling using UiExceptionHandlers
getUI().ifPresent(currentUi -> currentUi.access(() -> {
// should be removed manually because fileDownloaderRemoveHandler will not be executed
// due to DownloadFinishedEvent will not be published
removeFromParent();
throw new RuntimeException(e);
}));
return false;
} else {
// exception is handled in listener
return true;
}
} finally {
response.getOutputStream().close();
}
return true;
}
return false;
};
ui.getSession().addRequestHandler(requestHandler);
getContent().setHref("./" + identifier);
}
}
Create a FixedDownloader bean:
public class FixedDownloader extends DownloaderImpl {
public void download(DownloadDataProvider dataProvider,
String resourceName,
@Nullable DownloadFormat downloadFormat) {
checkUIAccess();
boolean showNewWindow = this.newWindow;
// Replace all invalid 'resourceName' characters with underscores before downloading.
// 'resourceName' parameter value will be used in URI (generated when resource is registered)
// in a way that the name is the last segment of the path
resourceName = normalize(resourceName);
if (useViewList) {
String fileExt;
if (downloadFormat != null) {
fileExt = downloadFormat.getFileExt();
} else {
fileExt = FilenameUtils.getExtension(resourceName);
}
showNewWindow = viewFilePredicate.test(StringUtils.lowerCase(fileExt));
}
if (downloadFormat != null) {
if (StringUtils.isEmpty(FilenameUtils.getExtension(resourceName))) {
resourceName += "." + downloadFormat.getFileExt();
}
}
FixedFileDownloader fileDownloader = new FixedFileDownloader();
UI ui = UI.getCurrent();
ui.add(fileDownloader);
fileDownloader.setFileName(resourceName);
fileDownloader.setCacheMaxAgeSec(uiProperties.getFileDownloaderCacheMaxAgeSec());
fileDownloader.addDownloadFinishedListener(this::fileDownloaderRemoveHandler);
fileDownloader.setFileNotFoundExceptionHandler(this::handleFileNotFoundException);
StreamResource resource = new StreamResource(resourceName, dataProvider::getStream);
if (downloadFormat != null && StringUtils.isNotEmpty(downloadFormat.getContentType())) {
resource.setContentType(downloadFormat.getContentType() + DEFAULT_CHARSET_SUFFIX);
} else {
resource.setContentType(FileTypesHelper.getMIMEType(resourceName) + DEFAULT_CHARSET_SUFFIX);
}
if (showNewWindow && isBrowserSupportsPopups() || isIPhone()) {
fileDownloader.viewDocument(resource);
} else {
fileDownloader.downloadFile(resource);
}
}
}
Register FixedDownloader bean in your app configuration class:
@Bean("flowui_Downloader")
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@Primary
public Downloader downloader() {
return new FixedDownloader();
}
Don’t forget to set application property to be able to override spring beans:
spring.main.allow-bean-definition-overriding=true
Best regards,
Dmitriy
Hi @d.kremnev
Thank you for the workaround.
How long is planned to offer the community a known damaged update to 2.7.5 ? I would suggest, to remove this version for the moment, until this is fixed.
What are the plans ?
Regards
Felix
Hi Felix,
Unfortunately we cannot remove a release, it’s already in public repositories.
We are building the new release 2.7.6 with the fix. It will be available tomorrow.
Regards,
Konstantin
@krivopustov Sorry, this question is not fully related to that topic: With how much delay does the more reliable global repository gets updated to new artifact versions?
I can find 2.7.6 on https://nexus.jmix.io, but not yet on https://global.repo.jmix.io/. Is it a question of minutes, hours, days?
It’s a question of hours. We do last tests on https://nexus.jmix.io and then publish to global.