FYI, this flaw was recognized by the expert group, and
in JSP 1.2, JspException has the following new constructors/methods:
public JspException(String message, Throwable rootCause);
public JspException(Throwable rootCause);
public Throwable getRootCause();
Unfortunately, this won't help in a JSP1.1 environment :-(
-- Pierre
"Deadman, Hal" wrote:
>
> The current way Struts tags try to store the root exception is to store the
> exception as a request attribute. This is done primarily in the taglib
> because the tags must all throw JspException which doesn't allow for a
> nested or root exception to be stored along with the message. My concern
> with the exceptions being put in the request object is that they can get
> overwritten when tags are nested.
>
> Couldn't we extend JspException and throw that instead and pass the
> exception that caused the problem as an optional argument to the
> constructor? That would make it behave like ServletException. When the
> exception was eventually caught the error handling code could call
> getRootCause() on all ServletExceptions or "StrutsJspExceptions". This would
> involve looping through exceptions because the nesting could be n levels
> deep. This code would be application specific. Changing cases of throw
> JspExeption to throw StrutsJspException would involve lots of modifications
> to the code but they would be straightforward and I don't think it would
> break anything as long as the code that puts the exception in the request
> was left alone.
>
> Below are a couple of the many examples where JspExceptions are caught and
> re-thrown and in one example put in the request object. I also included a
> possible implementation of StrutsJspException. Am I off base? Am I missing
> something? I would like to hear some feedback about whether this is
> something worth doing or why it isn't necessary.
>
> Thanks, Hal
>
> >From Action.java:
> /**
> * The request attributes key under which Struts custom tags might store
> * a <code>Throwable</code> that caused them to report a JspException at
> * runtime. This value can be used on an error page to provide more
> * detailed information about what really went wrong.
> */
> public static final String EXCEPTION_KEY =
> "org.apache.struts.action.EXCEPTION";
>
> >From Include.java
> // Include the contents of the corresponding actual page
> try {
> pageContext.include(forward.getPath());
> } catch (Exception e) {
> throw new JspException
> (messages.getMessage("includeTag.include",
> name, e.toString()));
> }
>
> >From IncludeTag.java
> URLConnection conn = null;
> try {
> conn = url.openConnection();
> conn.setAllowUserInteraction(false);
> conn.setDoInput(true);
> conn.setDoOutput(false);
> conn.connect();
> } catch (Exception e) {
> pageContext.setAttribute(Action.EXCEPTION_KEY, e,
> PageContext.REQUEST_SCOPE);
> throw new JspException
> (messages.getMessage("include.open",
> url.toString(), e.toString()));
> }
>
> File: StrutsJspException.java
> /****************************************************************
> * org.apache.struts.util.StrutsJspException *
> * *
> ****************************************************************/
> package org.apache.struts.util;
>
> import javax.servlet.jsp.JspException;
>
> public class StrutsJspException extends JspException
> {
> /**
> * Nested error
> */
> private Throwable nested;
>
> /**
> * Constructor
> */
> public StrutsJspException()
> {
> }
>
> /**
> * Constructor
> *
> * @param nested Exception from actual Exception
> */
> public StrutsJspException(Throwable nested)
> {
> this.nested = nested;
> }
>
> /**
> * Constructor
> *
> * @param s Description of error
> * @param nested Exception from actual Exception
> */
> public StrutsJspException(String s, Throwable nested)
> {
> super(s);
> this.nested = nested;
> }
>
> /**
> * Constructor
> *
> * @param s Description of error
> */
> public StrutsJspException(String s)
> {
> super(s);
> }
>
> /**
> * Retrieves nested error
> *
> * @return Nested error message
> */
> public Throwable getRootCause()
> {
> return nested;
> }
> }