Hot questions for Using JasperReports in struts2

Question:

I am using struts2 and jasper report in a little web application. I am getting the following error when I am trying to export the report. Report is exported successfully but an error is printed in the log and struts unable to redirect to the success page after executing the action as well.

I have searched this through the internet but I was unable to clarify this. Could anybody please help me to clarify this.

    ERROR Dispatcher - Exception occurred during processing request: Cannot call sendRedirect() after the response has been committed
java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
   at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:482)
   at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:137)
   at org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper.sendRedirect   (SaveContextOnUpdateOrErrorResponseWrapper.java:74)
   at org.apache.struts2.dispatcher.ServletRedirectResult.sendRedirect(ServletRedirectResult.java:243)
   at org.apache.struts2.dispatcher.ServletRedirectResult.doExecute(ServletRedirectResult.java:226)
   at org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:186)
   at org.apache.struts2.dispatcher.ServletRedirectResult.execute(ServletRedirectResult.java:161)
   at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:367)
   at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:271)
   at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
   at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
   at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:176)
   at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
   at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
   at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
   at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept   (AnnotationValidationInterceptor.java:68)


<struts>

<package name="user" namespace="/" extends="struts-default">

    <action name="testJPReport" class="testUserSupport" method="exportReportAsPdf">
        <result name="success">report.jsp</result>
    </action>
</package>
</struts>


    <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

<bean id="testUserSupport"
      class="net.lavanya.app.lav.report.web.TestUserAction">
</bean>

public class TestUserAction  extends ExportSupport{

public String exportReportAsPdf() {
    Map<String, Object> param = new HashMap<>();
    try {
        DataBeanMaker dataBeanMaker = new DataBeanMaker();
        ArrayList<Test> dataBeanList = dataBeanMaker.getTestDataBeanList();
        processReport(ReportTypeEnum.PDF, dataBeanList, "test", param);

    } catch (Exception exception) {
        exception.printStackTrace();
    }
    return SUCCESS;
}

}

package net.test.app.report.web;


import com.opensymphony.xwork2.ActionSupport;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

 public class ExportSupport extends ActionSupport implements     ServletResponseAware, ServletRequestAware {

    private HttpServletResponse httpServletResponse;
    private HttpServletRequest httpServletRequest;
    private String contentType = "APPLICATION/OCTET-STREAM";


@Override
public void setServletResponse(HttpServletResponse httpServletResponse) {
    this.httpServletResponse = httpServletResponse;
}

@Override
public void setServletRequest(HttpServletRequest httpServletRequest) {
    this.httpServletRequest = httpServletRequest;
}

    public void processReport(ReportTypeEnum reportTypeEnum, List<?>      beansList, String reportName, Map<String, Object> parameters) throws       Exception {
        switch (reportTypeEnum) {
            case PDF:
                processReportAsPDF(beansList, reportName, parameters);
                break;
            default:
                throw new RuntimeException("Un supported report type");
    }
}

private void processReportAsPDF(List<?> beansList, String reportName, Map<String, Object> parameters) throws Exception {
    System.out.println(">>>>>>>Start processing of pdf report!");

    JRBeanCollectionDataSource beanColDataSource = new JRBeanCollectionDataSource(beansList);
    JasperDesign jasperDesign = JRXmlLoader.load(getJasperFilePath(reportName));
    JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
    JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, beanColDataSource);
    setResponseHeaderData(reportName, ReportTypeEnum.PDF);
    ServletOutputStream sos = httpServletResponse.getOutputStream();
    JasperExportManager.exportReportToPdfStream(jasperPrint, sos);
    sos.flush();
    sos.close();
    httpServletResponse.getOutputStream().flush();
    httpServletResponse.getOutputStream().close();

    System.out.println(">>>>>>>End processing of pdf report!");
    return;

}

private InputStream getJasperFilePath(String reportName) throws FileNotFoundException {
    System.out.println(">>>>>>> Path : " + httpServletRequest.getSession().getServletContext().getRealPath("/reports/" + reportName + ".jrxml"));
    return new FileInputStream(httpServletRequest.getSession().getServletContext().getRealPath("/reports/" + reportName + ".jrxml"));
}

private void setResponseHeaderData(String reportName, ReportTypeEnum reportTypeEnum) {
    httpServletResponse.setContentType(contentType);
    StringBuilder headerBuilder = new StringBuilder();
    headerBuilder.append("Attachment;Filename=").append("\"").append(reportName).append(".").
            append(reportTypeEnum.getReportType()).append("\"");

    httpServletResponse.setHeader("Content-Disposition", headerBuilder.toString());
    System.out.println(">>>>>>>End of setting response headers for report download");
}
}

Answer:

I could not find the sendRedirect in your code. Any way please consider that there is only one http response for every HTTP request you may need some JavaScript solution in the client side.

The export action, or generally the stream result type action should look as below:

 @Action(value = "sample-export", results = { @Result(name = "success", type = "stream", params = {
            "inputName", "inputStream", 
            "contentType",   "${exportContentType}; charset=UTF-8", 
            "Content-Disposition", "attachment; filename=\"${filename}\"", 
            "contentDisposition","attachment; filename=\"${filename}\"", 
            "bufferSize", "2048" }) })
    public String export() throws ClientException {

        inputStream = exportInputStream();

        return SUCCESS;

    }
    //Setter and getters for inputStream (java.io.InputStream)

As you see returning success will not and actually should not redirect user to a new page, user sends a request and gets an stream (PDF for example) as a result.

If you want to redirect you need to do more by javascript, or change the download steps, please see Is it possible in Struts 2 to have a result that downloads a file (stream) *and* redirects? which may help. By changing your download steps, I mean you can save the file on a temp location on your server, redirect user to a final page and put the download link there.

Question:

I'm working with a struts 2.3.4.1 and am using the struts2-jasperreports-plugin to display a pre-compiled report. Fonts have been giving me issues, which I found was supposedly fixed in Jasperreports 6 (specifically issues with Calibri). Because I'm on a legacy system running java 6, the last version I can use is 6.2.2. But when I try to display my report, I get java.lang.NoSuchMethodError: net.sf.jasperreports.engine.util.JRLoader.loadObject(Ljava/lang/String;)Ljava/lang/Object; org.apache.struts2.views.jasperreports.JasperReportsResult.doExecute(JasperReportsResult.java:323), which seems to be a function called by the struts2-jasperreports-plugin that doesn't exist in jasperreports 6+. I've been looking around, but cannot find out if/how to change this behavior and am beginning to think that I need to update the version of my plugin.

Is there a way to change the function called by the plugin, or am I going to need to change the version of struts to get the behavior I expect? Is it possible to write an adapter for a plugin?


Answer:

After some more troubleshooting, I found https://stackoverflow.com/a/37864625/892327 in which an adapter was made using existing code, which I got from https://web.archive.org/web/20180523111530/http://grepcode.com/file/repo1.maven.org/maven2/net.sf.jasperreports/jasperreports/6.1.0/net/sf/jasperreports/engine/util/JRLoader.java/, and added the missing loadObject(String fileName) function as an adapter for the loadFromFile(String fileName). Which cleared the NoSuchMethodError.

However, the original issue java.lang.ArrayIndexOutOfBoundsException: 0 sun.font.ExtendedTextSourceLabel.createCharinfo(ExtendedTextSourceLabel.java:592 returned, which was "fixed" by changing the version of Java I was running, found at Error generating JasperReport in Development mode.

Because I'm working with a legacy system that runs on Java 6, I've given up since the original issue is JRE based and not a bad Jasperreports library or struts plugin.

Question:

I am trying to configure Struts 2 with jasper. I have tried this using a little example but I got an error I was unable to recover this after spending two days on it. I have mentioned the error log and other code examples I have used.

Unable to load configuration. - [unknown location]
at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:70)
at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:429)
at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:471)
at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:74)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.init(StrutsPrepareAndExecuteFilter.java:51)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:273)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:254)
at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:372)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:98)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4562)
at org.apache.catalina.core.StandardContext$2.call(StandardContext.java:5240)
at org.apache.catalina.core.StandardContext$2.call(StandardContext.java:5235)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
    Caused by: Parent package is not defined: jasperreports-default - [unknown location]
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.buildPackageContext(XmlConfigurationProvider.java:660)
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.addPackage(XmlConfigurationProvider.java:508)
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadPackages(XmlConfigurationProvider.java:290)
at org.apache.struts2.config.StrutsXmlConfigurationProvider.loadPackages(StrutsXmlConfigurationProvider.java:112)
at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:239)
at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:67)
... 16 more
    Jan 28, 2015 7:36:54 PM org.apache.catalina.core.StandardContext filterStart
    SEVERE: Exception starting filter struts2
    Unable to load configuration. - [unknown location]
at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:483)
at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:74)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.init(StrutsPrepareAndExecuteFilter.java:51)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:273)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:254)
at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:372)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:98)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4562)
at org.apache.catalina.core.StandardContext$2.call(StandardContext.java:5240)
at org.apache.catalina.core.StandardContext$2.call(StandardContext.java:5235)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
    Caused by: Unable to load configuration. - [unknown location]
at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:70)
at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:429)
at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:471)
... 14 more
    Caused by: Parent package is not defined: jasperreports-default - [unknown location]
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.buildPackageContext(XmlConfigurationProvider.java:660)
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.addPackage(XmlConfigurationProvider.java:508)
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadPackages(XmlConfigurationProvider.java:290)
at org.apache.struts2.config.StrutsXmlConfigurationProvider.loadPackages(StrutsXmlConfigurationProvider.java:112)
at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:239)
at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:67)

struts.xml

    <action name="TestReportExportSupport!*" class="TestReportExportSupport">

        <result name="success" type="jasper">
            <param name="location">our_compiled_template.jasper</param>
            <param name="dataSource">myList</param>
            <param name="format">PDF</param>
        </result>

    </action>
</package>
</struts>

Action class public class JasperAction extends ActionSupport {

/** List to use as our JasperReports dataSource. */
private List<Person> myList;

public String execute() throws Exception {

    // Create some imaginary persons.
    Person p1 = new Person(new Long(1), "Patrick", "Lightbuddie");
    Person p2 = new Person(new Long(2), "Jason", "Carrora");
    Person p3 = new Person(new Long(3), "Alexandru", "Papesco");
    Person p4 = new Person(new Long(4), "Jay", "Boss");

    // Store people in our dataSource list (normally they would come from a database).
    myList = new ArrayList<Person>();
    myList.add(p1);
    myList.add(p2);
    myList.add(p3);
    myList.add(p4);

    // Normally we would provide a pre-compiled .jrxml file
    // or check to make sure we don't compile on every request.
    try {
        JasperCompileManager.compileReportToFile(
                "S2_WEBAPP/jasper/our_jasper_template.jrxml",
                "S2_WEBAPP/jasper/our_compiled_template.jasper");
    } catch (Exception e) {
        e.printStackTrace();
        return ERROR;
    }

    return SUCCESS;
}

public List<Person> getMyList() {
    return myList;
}

}

Jars used 1. jasperreports-1.2.5.jar 2. itext-1.3.jar 3. jdt-compiler.jar

Can anybody help me to resolve this. I tried this out 2 days... with lot's of solutions given in the internet.


Answer:

Hi I found the issue here. I included the struts2-jasperreports-plugin-2.1.8.1.jar and jdt-compiler-3.1.1.jar. I missed the struts2-jasperreports-plugin-2.1.8.1.jar. I also added -XX:PermSize=256m -XX:MaxPermSize=256m to server for raise perm space(But this is not related with the above issue).

Thanks Dave for your clue.