Next, let’s look at our JSP files.  There are only three of them: index.jsp which is the index page of the web application, captureme.jsp, which is the JSP we will render to a String, and captureinclude.jsp, which we will use to prove we can include JSPs inside a rendered JSP.

/src/main/webapp/WEB-INF/jsp/index.jsp

<html>
<head>
    <style>
        a {text-decoration: none};
    </style>
</head>
<body>
This is the outer JSP that was served for the request.
<br>
It can be found at /src/main/webapp/WEB-INF/jsp/index.jsp
<br>
Value of the model attribute "message" : ${message}
<br>
Note that the outer and inner jsp pages can have different models
<br>
The capture JSP page follows:
<hr>
${jspoutput}
<hr>
Now we are back to the outer jsp page (index.jsp)
<hr>
<a href="?locale=en_US"><button>Use Locale en_US</button></a>&nbsp;<a href="?locale=es_MX"><button>Use Locale es_MX</button></a>&nbsp;<a href="?locale=fr_FR"><button>Use Locale fr_FR</button></a>&nbsp;<a href="?locale=de_DE"><button>Use Locale de_DE</button></a>
</body>
</html>

The important bits are on lines 12 and 18, which uses the model passed to index.jsp to output a message, and also the String that is the rendered JSP (jspoutput).  Index.jsp is rendered as the response to an end-user request (in other words, a normal Spring JSP).

/src/main/webapp/WEB-INF/jsp/capture/captureme.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<html>
<body>
<h1><spring:message code="welcome.message"/></h1>
This is the rendered JSP page, found at /src/main/webapp/WEB-INF/jsp/captureme.jsp
<br>
The welcome message above was rendered using locale ${localeUsed}
<br>
Here is the value of the model attribute "jspMessage": ${jspMessage}
<c:if test="${!empty costMessage}">
<br>
Here is the value of the model attribute "costMessage" in US Dollars, formatted for the given locale: <fmt:formatNumber type="currency" currencyCode="USD" value="${costMessage}"/>
<br>
Here is the value of the model attribute "costMessage" in Euros, formatted for the given locale: <fmt:formatNumber type="currency" currencyCode="EUR" value="${costMessage}"/>
<br>
Here is the value of the model attribute "costMessage" in Pesos, formatted for the given locale: <fmt:formatNumber type="currency" currencyCode="MXN" value="${costMessage}"/>
</c:if>
<br>
<jsp:include page="/WEB-INF/jsp/capture/captureinclude.jsp"/>
</body>
</html>

This file, captureme.jsp, is the one that we want to render into a String.  We’ll store that  String into the model of index.jsp as the attribute “jspoutput” (see index.jsp above).  The JSP is simple and there is no magic here, but I’ll point out some parts here to prove that we are matching the goals of the tutorial.  Remember that we are rendering this JSP without access to any end-user request.

Lines 1-3: Notice that we are including normal taglibs: c: and fmt: from JSTL, and spring: from Spring.  We can any taglib inside our String-rendered JSP.

Line 6: Here is where we output the “Welcome!” message.  Notice that the message changes based on the locale we pass to the JSP parser (we’ll see how that is done a bit later).  It also proves that the spring:message tag works.

Line 12 – 19: Here we are using the c:if and fmt:formatNumber tags to prove that the JSTL tags work inside the rendered JSP.  Note that we are formatting the number “costMessage”, which is part of the model for captureme.jsp (we’ll see where that is set later).  We are also rendering the number as US Dollars, Euros, and Pesos to show how the localization works with currency, based on the Locale we pass in (again, we’ll see how to set the Locale later).

Line 21: We are including another JSP here, just to prove that we can include another JSP inside the rendered JSP.  The included file (see below) is also a JSP fragment, so we prove that we can handle fragments.

Again, there is nothing magic about captureme.jsp.  It is a normal JSP file, and doesn’t require any special coding for us to use it as a String-rendered JSP.

/src/main/webapp/WEB-INF/jsp/capture/captureinclude.jsp

I'm another JSP (captureinclude.jsp)included by captureme.jsp!

This is the simple JSP fragment that is included by captureme.jsp, for completeness.

Here is the total output of index.jsp looks like, with the output of the rendered JSP, that we are expecting (French Locale is shown).

IndexJsp

Note that captureme.jsp is NOT a jsp:include or anything like that.  The inner part of this page (starting with “Bienvenue!”) is a String that we filled with the value of the rendered JSP captureme.jsp.  Make sure you understand the difference, as this is the crux of the tutorial.

It would be easy just to jsp:include the captureme.jsp page inside index.jsp.  We aren’t doing that.  We have a String that represents captureme.jsp that we could easily show on a web page, print to the console, or send in an email.  Index.jsp only knows it as the String named “jspoutput”.

Pages: 1 2 3

20 Responses to “Render and capture the output of a JSP as a String”

  1. Hi, i like the tutorial. I almost gave up and tried an other way.
    With this i can use the same jsp for the “real” page by including it and i can return the page-content encoded as a part of an json object called by ajax.
    I would like to use it and create a kind of library to have a tested maven artifact. That artifact i would like to use as a dependency for (an) other project(s).
    The only thing is, in the git-reposetory is no License included. Would you add a apache, mit or lgpl license?

  2. Apache license added. Have fun. Shoot me a copy when you get your library working.

  3. Thanks for sharing, using mockresponse is a neat idea.

  4. Bob, first of all, thanks for writing this tutorial. Bonus points for being so thorough. I came here looking to do the exact same thing as your first poster, David. Anyway, I’ve encountered one big problem. The render(…) method kicks off the servlet container’s own include(…) method which ultimately causes a MalformedURLException. Here’s a snippet of the stack trace:

    ——————————————————-
    java.net.MalformedURLException: Path does not start with a “/” character
    com.zeroturnaround.javarebel.vS.a(JRebel:50)
    com.zeroturnaround.javarebel.pY.getResource(JRebel:108)
    org.eclipse.jetty.webapp.WebAppContext$Context.getResource(WebAppContext.java)
    org.apache.jasper.servlet.JspServlet._serviceJspFile(JspServlet.java:447)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:380)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:538)
    org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:478)
    org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:119)
    org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:517)
    org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:225)
    org.eclipse.jetty.server.handler.ContextHandler.__doHandle(ContextHandler.java:937)
    org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java)
    org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:406)
    org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:183)
    org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:871)
    org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
    org.eclipse.jetty.server.Dispatcher.include(Dispatcher.java:195)
    … [the rest omitted] …
    ——————————————————-

    (FYI: JRebel isn’t at fault; I get the same whether it’s enabled or not)

    I’ve debugged my custom ViewResolver’s getUrlForView(…) method, and it always returns a path starting with a “/” character (i.e.: starts with “/WEB-INF/”). So I have no idea how to go forward from here. Any idea what the problem might be?

    Michael

    • Hmm.. that’s a tough one. My first guess would be that the context in the web.xml file doesn’t start (or possibly end) with a “/”, so you may want to look there.

      I also seem to remember that in some early versions of Tomcat that there was a bug getting to internal resources unless they originated within the container itself (as a security measure). Not sure about Jetty though, as I don’t normally use it.

      Check out the web.xml file’s context setting and see if that works. In the meantime, I’ll try to set up a Jetty instance (I don’t have JRebel, but you said it happened even without, so that’s obviously not it).

      Are you using Eclipse’s WTP there? Or just building a war and running it outside?

  5. Hello bob, i’ve use your SwallowingJspRenderer in Tomcat 7.0 and it’s work great. But, when i try to using JBOSS EAP 6.0 or JBOSS AS 7.x.x as a web server, i’ve got error below :

    javax.servlet.ServletException: Original SevletRequest or wrapped original ServletRequest not passed to RequestDispatcher in violation of SRV.8.2 and SRV.14.2.5.1

    What should i do to solve this problem? Because i’ll use JBOSS EAP 6.0 on production’s environment. Thanks 🙂

  6. Hi Apri,

    I haven’t used JBoss in a while, so I haven’t seen this error. One of the JBoss forums suggests this can fixed by turning off strict server compliance with “-Dorg.apache.catalina.STRICT_SERVLET_COMPLIANCE=false” in the startup script though.

    (Yeah, I know, looks weird with org.apache.catalina in it)

    Bob

    • Thank you for your response bob, i’ve add -Dorg.apache.catalina.STRICT_SERVLET_COMPLIANCE=false in standalone.conf but i’ve got another error :

      java.lang.ClassCastException: com.bankbjb.itcore.cashportal.common.MockIncludedHttpServletRequest cannot be cast to javax.servlet.ServletRequestWrapper

      Any idea to solve this error? thanks again bob 🙂

      • @Apri,

        I’m not sure why it would be casting MockIncludedHttpServletRequest (MIHSR for short) to ServletRequestWrapper. MIHSR doesn’t implement wrapper, but is (ultimately) derived directly from SerlvetRequest.

        In theory, you could modify MIHSR to implement ServletWrapper as well, though. Can you tell where this is happening? Is there more to the stack trace?

        Bob

        • helo rob,
          sorry for late response, i’ve got stack trace from jboss log :

          09:56:33,696 INFO [stdout] (http-/127.0.0.1:8089-5) SwallowingJspRenderer: com.bankbjb.itcore.cashportal.common.MockIncludedHttpServletRequest cannot be cast to javax.servlet.ServletRequestWrapper
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) java.lang.ClassCastException: com.bankbjb.itcore.cashportal.common.MockIncludedHttpServletRequest cannot be cast to javax.servlet.ServletRequestWrapper
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationFilterFactory.createFilterChain(ApplicationFilterFactory.java:164)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:827)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:720)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:657)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at com.bankbjb.itcore.cashportal.common.SwallowingJspRenderer.render(SwallowingJspRenderer.java:91)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at com.bankbjb.itcore.cashportal.controller.CredentialControler.renderView(CredentialControler.java:341)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at com.bankbjb.itcore.cashportal.controller.CredentialControler.showView(CredentialControler.java:296)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at com.bankbjb.itcore.cashportal.controller.CredentialControler.showView(CredentialControler.java:290)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at com.bankbjb.itcore.cashportal.controller.CredentialControler.add(CredentialControler.java:133)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at java.lang.reflect.Method.invoke(Method.java:601)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:212)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:679)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:931)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at java.lang.Thread.run(Thread.java:722)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) java.io.IOException: java.lang.ClassCastException: com.bankbjb.itcore.cashportal.common.MockIncludedHttpServletRequest cannot be cast to javax.servlet.ServletRequestWrapper
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at com.bankbjb.itcore.cashportal.common.SwallowingJspRenderer.render(SwallowingJspRenderer.java:98)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at com.bankbjb.itcore.cashportal.controller.CredentialControler.renderView(CredentialControler.java:341)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at com.bankbjb.itcore.cashportal.controller.CredentialControler.showView(CredentialControler.java:296)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at com.bankbjb.itcore.cashportal.controller.CredentialControler.showView(CredentialControler.java:290)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at com.bankbjb.itcore.cashportal.controller.CredentialControler.add(CredentialControler.java:133)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at java.lang.reflect.Method.invoke(Method.java:601)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:212)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
          09:56:33,696 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:679)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:931)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at java.lang.Thread.run(Thread.java:722)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) Caused by: java.lang.ClassCastException: com.bankbjb.itcore.cashportal.common.MockIncludedHttpServletRequest cannot be cast to javax.servlet.ServletRequestWrapper
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationFilterFactory.createFilterChain(ApplicationFilterFactory.java:164)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:827)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:720)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:657)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) at com.bankbjb.itcore.cashportal.common.SwallowingJspRenderer.render(SwallowingJspRenderer.java:91)
          09:56:33,711 ERROR [stderr] (http-/127.0.0.1:8089-5) … 37 more

          thanks again rob 🙂

          • @Apri,

            I’ve been looking around, and to be honest I am stumped. RequestDispatcher.include (which is where the exception starts) should accept any ServletRequest, without it being a wrapper. I’m not sure why JBoss would require such. Maybe somebody on here that uses JBoss can answer this?

            Bob

  7. Taimo Kolsar says:

    I had the following problem:
    In a Spring MVC app I had some SVG-s generated by JSP-s. Now I was asked to add the SVG-s to a PDF, which was generated in a controller.

    So I needed exactly the solution. But I tried a simpler one, and it seems to work. Here is my solution:

    1. I implemented javax.servlet.http.HttpServletResponse wrapping PrintWriter, and created content only for getWriter() method:

    public class HttpServletResponseOutput implements HttpServletResponse {

    private PrintWriter printWriter;

    public HttpServletResponseOutput(StringWriter stringWriter){
    this.printWriter = new PrintWriter(stringWriter);
    }

    @Override
    public PrintWriter getWriter() throws IOException {
    return this.printWriter;
    }

    }

    2. I autowired another controller to the main controller:

    @Controller(value = “anotherController”)
    public class AnotherController {…

    @Controller
    public class MainController {
    @Autowired
    private VastController vastController;

    3. Inside the controller method:

    RequestDispatcher dispatcher = request.getRequestDispatcher(“/WEB-INF/views/svg/graph.jsp”); // Absolute path here. It’s not very nice, but it works.
    StringWriter stringWriter = new StringWriter();
    HttpServletResponse intermediateResponse = new HttpServletResponseOutput(stringWriter);
    anotherController.getGraph(model, request, intermediateResponse);
    try{
    dispatcher.include(request, intermediateResponse);
    } catch(Exception e){
    log.error(e.getMessage());
    }
    String graph = stringWriter.toString();
    // This String contains the SVG now

  8. Taimo Kolsar says:

    Sorry for a typo,
    In the 2. point it should be:
    @Autowired
    private AnotherController anotherController;

  9. Hi Bob,

    My project wants the static html rendered out of jsp. Will this source code helps in capturing HTML.

    Thanks in advance.
    Sudha.

    • It should. The “string” that comes out of the JSP renderer is simply the HTML that the JSP would have produced. You could leave out the model stuff if you don’t need it.

  10. Thanks for the tutorial, but messageSource doesn’t work for me (configured it as bean in my java config).

    It works when i use the jsps like usual, but it does not when i want to render jsps to a String.

    Any ideas?

  11. Hi Bob,

    I deployed your code and when I request http://localhost:8080/capturejsp/
    Browser only shows content of index.jsp. The text below line “The capture JSP page follows:” is empty.

    I checked Console and saw this warning:
    |WARN |oting.util.SwallowingHttpServletResponse||Ignoring call to sendError(405, JSPs only permit GET POST or HEAD)

    I think that the mock request object does not have any HTTP method. Then, I change file MockIncludedHttpServletRequest.java as follows:

    public class MockIncludedHttpServletRequest extends MockHttpServletRequest {

    public MockIncludedHttpServletRequest() {
    super();
    this.setMethod(“GET”);
    }

    Now, JSP files are renderred.

  12. Steven Wright says:

    Hi, thanks for this tutorial, it works like a charm. I have one issue I could use your help with please. I am using this a secondary way of rendering content in a Spring App. Basically in some cases we use the regular Spring renderer and in others we have to use this.

    What I’d like to know is if its possible that the bean annotation I use for formatting can be applied to this as well?

    I have a custom formatter and annotation for phone number. The formatter is added to Springs registry like this:

    @Override
    public void addFormatters(FormatterRegistry registry)
    {
    registry.addFormatterForFieldAnnotation(new PhoneNumberFormatAnnotationFormatterFactory());
    registry.addFormatterForFieldAnnotation(new BinaryIntFormatterAnnotationFormatterFactory());
    }

    How do I accomplish this in the context of the swallowing renderer?

    Thanks for any advice you can offer.

    • You know, I’ve looked at this several times over the last couple of months, and I can’t find where the FormatterRegistry is attached. There must be one somewhere that could be modified for the Swallowing renderer, I just can’t find it very easily. If you breakpoint your normal addFormatterFor… calls, you might be able to find it. Sorry I couldn’t be more helpful there.

Leave a Reply

Your email address will not be published. Required fields are marked *