There was the same problem ( File resolver in Jasper Reports 5.0.1 ), and after a few hours I found the answer in JasperReports sources.
LocalJasperReportsContext ctx = new LocalJasperReportsContext(DefaultJasperReportsContext.getInstance()); ctx.setClassLoader(getClass().getClassLoader()); ctx.setFileResolver(new FileResolver() { @Override public File resolveFile(String s) { return new File(s); } }); JasperReport jasperReport = (JasperReport) JRLoader.loadObject(jasperfile); JasperFillManager fillmgr = JasperFillManager.getInstance(ctx); JasperExportManager exmgr = JasperExportManager.getInstance(ctx);
Edit: The correct solution will include reporting the problem to the ticketing system of the plugins and possibly offering a patch to implement the solution.
Waiting for the patch to be accepted, you can extend the JasperReportsResult class and simply override the doExecute() method using the code above, with something like this:
protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception { // Will throw a runtime exception if no "datasource" property. TODO Best place for that is...? initializeProperties(invocation); LOG.debug("Creating JasperReport for dataSource = {}, format = {}", dataSource, format); HttpServletRequest request = (HttpServletRequest) invocation.getInvocationContext().get(ServletActionContext.HTTP_REQUEST); HttpServletResponse response = (HttpServletResponse) invocation.getInvocationContext().get(ServletActionContext.HTTP_RESPONSE); // Handle IE special case: it sends a "contype" request first. // TODO Set content type to config settings? if ("contype".equals(request.getHeader("User-Agent"))) { try (OutputStream outputStream = response.getOutputStream()) { response.setContentType("application/pdf"); response.setContentLength(0); } catch (IOException e) { LOG.error("Error writing report output", e); throw new ServletException(e.getMessage(), e); } return; } // Construct the data source for the report. ValueStack stack = invocation.getStack(); ValueStackDataSource stackDataSource = null; Connection conn = (Connection) stack.findValue(connection); if (conn == null) stackDataSource = new ValueStackDataSource(stack, dataSource, wrapField); if ("https".equalsIgnoreCase(request.getScheme())) { // set the the HTTP Header to work around IE SSL weirdness response.setHeader("CACHE-CONTROL", "PRIVATE"); response.setHeader("Cache-Control", "maxage=3600"); response.setHeader("Pragma", "public"); response.setHeader("Accept-Ranges", "none"); } // Determine the directory that the report file is in and set the reportDirectory parameter // For WW 2.1.7: // ServletContext servletContext = ((ServletConfig) invocation.getInvocationContext().get(ServletActionContext.SERVLET_CONFIG)).getServletContext(); ServletContext servletContext = (ServletContext) invocation.getInvocationContext().get(ServletActionContext.SERVLET_CONTEXT); String systemId = servletContext.getRealPath(finalLocation); Map parameters = new ValueStackShadowMap(stack); File directory = new File(systemId.substring(0, systemId.lastIndexOf(File.separator))); parameters.put("reportDirectory", directory); parameters.put(JRParameter.REPORT_LOCALE, invocation.getInvocationContext().getLocale()); // put timezone in jasper report parameter if (timeZone != null) { timeZone = conditionalParse(timeZone, invocation); final TimeZone tz = TimeZone.getTimeZone(timeZone); if (tz != null) { // put the report time zone parameters.put(JRParameter.REPORT_TIME_ZONE, tz); } } // Add any report parameters from action to param map. Map reportParams = (Map) stack.findValue(reportParameters); if (reportParams != null) { LOG.debug("Found report parameters; adding to parameters..."); parameters.putAll(reportParams); } ByteArrayOutputStream output; JasperPrint jasperPrint; LocalJasperReportsContext ctx = new LocalJasperReportsContext(DefaultJasperReportsContext.getInstance()); ctx.setClassLoader(getClass().getClassLoader()); ctx.setFileResolver(parameters.get()); JasperReport jasperReport = (JasperReport) JRLoader.loadObject(jasperfile); JasperFillManager fillmgr = JasperFillManager.getInstance(ctx); JasperExportManager exmgr = JasperExportManager.getInstance(ctx); // Fill the report and produce a print object try { JasperReport jasperReport = (JasperReport) JRLoader.loadObject(new File(systemId)); if (conn == null) { jasperPrint = fillmgr.fillReport(jasperReport, parameters, stackDataSource); } else { jasperPrint = fillmgr.fillReport(jasperReport, parameters, conn); } } catch (JRException e) { LOG.error("Error building report for uri {}", systemId, e); throw new ServletException(e.getMessage(), e); } // Export the print object to the desired output format try { if (contentDisposition != null || documentName != null) { final StringBuffer tmp = new StringBuffer(); tmp.append((contentDisposition == null) ? "inline" : contentDisposition); if (documentName != null) { tmp.append("; filename="); tmp.append(documentName); tmp.append("."); tmp.append(format.toLowerCase()); } response.setHeader("Content-disposition", tmp.toString()); } JRExporter exporter; if (format.equals(FORMAT_PDF)) { response.setContentType("application/pdf"); exporter = new JRPdfExporter(ctx); } else if (format.equals(FORMAT_CSV)) { response.setContentType("text/csv"); exporter = new JRCsvExporter(ctx); } else if (format.equals(FORMAT_HTML)) { response.setContentType("text/html"); // IMAGES_MAPS seems to be only supported as "backward compatible" from JasperReports 1.1.0 Map imagesMap = new HashMap(); request.getSession(true).setAttribute("IMAGES_MAP", imagesMap); exporter = new JRHtmlExporter(ctx); exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP, imagesMap); exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, request.getContextPath() + imageServletUrl); // Needed to support chart images: exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint); request.getSession().setAttribute("net.sf.jasperreports.j2ee.jasper_print", jasperPrint); } else if (format.equals(FORMAT_XLS)) { response.setContentType("application/vnd.ms-excel"); exporter = new JRXlsExporter(ctx); } else if (format.equals(FORMAT_XML)) { response.setContentType("text/xml"); exporter = new JRXmlExporter(ctx); } else if (format.equals(FORMAT_RTF)) { response.setContentType("application/rtf"); exporter = new JRRtfExporter(ctx); } else { throw new ServletException("Unknown report format: " + format); } Map exportParams = (Map) stack.findValue(exportParameters); if (exportParams != null) { LOG.debug("Found export parameters; adding to exporter parameters..."); exporter.getParameters().putAll(exportParams); } output = exportReportToBytes(jasperPrint, exporter); } catch (JRException e) { LOG.error("Error producing {} report for uri {}", format, systemId, e); throw new ServletException(e.getMessage(), e); } finally { try { conn.close(); } catch (Exception e) { LOG.warn("Could not close db connection properly", e); } } response.setContentLength(output.size()); // Will throw ServletException on IOException. writeReport(response, output); }
and then use the new extension as the Result in Struts. Check if the method is implemented correctly.
The final decision should include the use of the context instance installer in the Result object, or possibly a global instance of the static context accessible from the Result object.