You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2011/11/30 19:17:57 UTC

svn commit: r1208626 - in /myfaces/core/branches/2.0.x/impl/src: main/java/org/apache/myfaces/renderkit/ test/java/org/apache/myfaces/renderkit/

Author: lu4242
Date: Wed Nov 30 18:17:57 2011
New Revision: 1208626

URL: http://svn.apache.org/viewvc?rev=1208626&view=rev
Log:
MYFACES-3413 Default MyFaces Error handling throws NullPointerException during component tree when javax.el.Expression.getExpressionString() is null

Added:
    myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ErrorPageWriterTest.java   (with props)
    myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/NullReturningGetExpressionStringValueExpression.java   (with props)
Modified:
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java?rev=1208626&r1=1208625&r2=1208626&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java Wed Nov 30 18:17:57 2011
@@ -81,13 +81,13 @@ import org.apache.myfaces.view.facelets.
 /**
  * This class provides utility methods to generate the
  * MyFaces error and debug pages. 
- * 
+ *
  * @author Jacob Hookom (ICLA with ASF filed)
  * @author Jakob Korherr (refactored and moved here from javax.faces.webapp._ErrorPageWriter)
  */
 public final class ErrorPageWriter
 {
-    
+
     /**
      * This bean aims to generate the error page html for inclusion on a facelet error page via
      * <ui:include src="javax.faces.error.xhtml" />. When performing this include the facelet
@@ -99,26 +99,26 @@ public final class ErrorPageWriter
      */
     public static class ErrorPageBean implements Serializable
     {
-        
+
         private static final long serialVersionUID = -79513324193326616L;
 
         public String getErrorPageHtml() throws IOException
         {
             FacesContext facesContext = FacesContext.getCurrentInstance();
             Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
-            
+
             Throwable t = (Throwable) requestMap.get(EXCEPTION_KEY);
             if (t == null)
             {
                 throw new IllegalStateException("No Exception to handle");
             }
-            
+
             UIViewRoot view = (UIViewRoot) requestMap.get(VIEW_KEY);
-            
+
             StringWriter writer = new StringWriter();
             ErrorPageWriter.debugHtml(writer, facesContext, view, null, t);
             String html = writer.toString();
-            
+
             // change the HTML in the buffer to be included in an existing html page
             String body;
             try
@@ -130,7 +130,7 @@ public final class ErrorPageWriter
                 // no body found - return the entire html
                 return html;
             }
-            
+
             String head;
             try
             {
@@ -141,7 +141,7 @@ public final class ErrorPageWriter
                 // no head found - return entire body
                 return body;
             }
-            
+
             // extract style and script information from head and add it to body
             StringBuilder builder = new StringBuilder(body);
             // extract <style>
@@ -176,17 +176,17 @@ public final class ErrorPageWriter
                     break;
                 }
             }
-            
+
             return builder.toString();
         }
-        
+
     }
-    
+
     /**
      * The key which is used to store the ErrorPageBean in the view map of a facelet error page.
      */
     public static final String ERROR_PAGE_BEAN_KEY = "__myFacesErrorPageBean";
-    
+
     private static final String EXCEPTION_KEY = "javax.servlet.error.exception";
     public static final String VIEW_KEY = "org.apache.myfaces.error.UIViewRoot";
 
@@ -199,14 +199,14 @@ public final class ErrorPageWriter
     /**
      * Indicate the template name used to render the default error page used by MyFaces specific 
      * error handler implementation. 
-     * 
+     *
      * <p>See org.apache.myfaces.ERROR_HANDLING for details about
      * how to enable/disable it.</p>
      */
     @JSFWebConfigParam(defaultValue="META-INF/rsc/myfaces-dev-error.xml", since="1.2.4")
     private static final String ERROR_TEMPLATE_RESOURCE = "org.apache.myfaces.ERROR_TEMPLATE_RESOURCE";
 
-    private static String[] ERROR_PARTS;
+    private static String[] errorParts;
 
     private static final String DEBUG_TEMPLATE = "META-INF/rsc/myfaces-dev-debug.xml";
 
@@ -216,42 +216,42 @@ public final class ErrorPageWriter
     @JSFWebConfigParam(defaultValue="META-INF/rsc/myfaces-dev-debug.xml", since="1.2.4")
     private static final String DEBUG_TEMPLATE_RESOURCE = "org.apache.myfaces.DEBUG_TEMPLATE_RESOURCE";
 
-    private static String[] DEBUG_PARTS;
-    
+    private static String[] debugParts;
+
     private static final String REGEX_PATTERN = ".*?\\Q,Id:\\E\\s*(\\S+)\\s*\\].*?";
-    
+
     private final static String[] IGNORE = new String[] { "parent", "rendererType" };
-    
+
     private final static String[] ALWAYS_WRITE = new String[] { "class", "clientId" };
-    
+
     /**
      * Extended debug info is stored under this key in the request
      * map for every UIInput component when in Development mode.
      * ATTENTION: this constant is duplicate in javax.faces.component.UIInput
      */
     public static final String DEBUG_INFO_KEY = "org.apache.myfaces.debug.DEBUG_INFO";
-    
+
     /**
      * The number of facets of this component which have already been visited while
      * creating the extended component tree is saved under this key in the component's
      * attribute map.
      */
     //private static final String VISITED_FACET_COUNT_KEY = "org.apache.myfaces.debug.VISITED_FACET_COUNT";
-
-    private static final Map<UIComponent, Integer> visitedFacetCount = new HashMap<UIComponent, Integer>();
+    private static Map<UIComponent, Integer> visitedFacetCount = new HashMap<UIComponent, Integer>();
 
     /**
      * Indicate if myfaces is responsible to handle errors. 
      * See http://wiki.apache.org/myfaces/Handling_Server_Errors for details.
      */
-    @JSFWebConfigParam(defaultValue="false, on Development Project stage: true",expectedValues="true,false", since="1.2.4")
+    @JSFWebConfigParam(defaultValue="false, on Development Project stage: true",
+                       expectedValues="true,false", since="1.2.4")
     public static final String ERROR_HANDLING_PARAMETER = "org.apache.myfaces.ERROR_HANDLING";
 
     public ErrorPageWriter()
     {
         super();
     }
-    
+
     /**
      * Generates the HTML error page for the given Throwable 
      * and writes it to the given writer.
@@ -264,64 +264,17 @@ public final class ErrorPageWriter
     {
         debugHtml(writer, faces, faces.getViewRoot(), null,  e);
     }
-    
-    /*
-    private static void debugHtml(Writer writer, FacesContext faces, Throwable e, UIViewRoot view) throws IOException
-    {
-        _init(faces);
-        Date now = new Date();
-        for (int i = 0; i < ERROR_PARTS.length; i++)
-        {
-            if ("message".equals(ERROR_PARTS[i]))
-            {
-                String msg = e.getMessage();
-                if (msg != null)
-                {
-                    writer.write(msg.replaceAll("<", TS));
-                }
-                else
-                {
-                    writer.write(e.getClass().getName());
-                }
-            }
-            else if ("trace".equals(ERROR_PARTS[i]))
-            {
-                _writeException(writer, e);
-            }
-            else if ("now".equals(ERROR_PARTS[i]))
-            {
-                writer.write(DateFormat.getDateTimeInstance().format(now));
-            }
-            else if ("tree".equals(ERROR_PARTS[i]))
-            {
-                if (view != null)
-                {
-                    _writeComponent(faces, writer, view, _getErrorId(e));
-                }
-            }
-            else if ("vars".equals(ERROR_PARTS[i]))
-            {
-                _writeVariables(writer, faces, view);
-            }
-            else if ("cause".equals(ERROR_PARTS[i]))
-            {
-                _writeCause(writer, e);
-            }
-            else
-            {
-                writer.write(ERROR_PARTS[i]);
-            }
-        }
-    }*/
-    
-    private static void debugHtml(Writer writer, FacesContext faces, UIViewRoot view, Collection<UIComponent> components, Throwable... exs) throws IOException
+
+    private static void debugHtml(Writer writer, FacesContext faces, UIViewRoot view,
+                                  Collection<UIComponent> components, Throwable... exs) throws IOException
     {
         _init(faces);
         Date now = new Date();
 
-        for (int i = 0; i < ERROR_PARTS.length; i++)
+        for (int i = 0; i < errorParts.length; i++)
         {
-            if ("view".equals((ERROR_PARTS[i]))) {
+            if ("view".equals((errorParts[i])))
+            {
                 if (faces.getViewRoot() != null)
                 {
                     String viewId = faces.getViewRoot().getViewId();
@@ -345,9 +298,9 @@ public final class ErrorPageWriter
                     writer.write("phaseId=" + faces.getCurrentPhaseId());
                     writer.write("<br/>");
                     writer.write("<br/>");
-                }    
+                }
             }
-            else if ("message".equals(ERROR_PARTS[i]))
+            else if ("message".equals(errorParts[i]))
             {
                 boolean printed = false;
                 //Iterator<UIComponent> iterator = null;
@@ -362,13 +315,6 @@ public final class ErrorPageWriter
                     {
                         writer.write("<br/>");
                     }
-                    //if (iterator != null)
-                    //{
-                    //    UIComponent uiComponent = iterator.next();
-                    //    if (uiComponent != null) {
-                    //        _writeComponent(faces, writer, uiComponent, null, /* writeChildren */false);
-                    //    }
-                    //}
                     if (msg != null)
                     {
                         writer.write(msg.replaceAll("<", TS));
@@ -380,7 +326,7 @@ public final class ErrorPageWriter
                     printed = true;
                 }
             }
-            else if ("trace".equals(ERROR_PARTS[i]))
+            else if ("trace".equals(errorParts[i]))
             {
                 boolean printed = false;
                 for (Throwable e : exs)
@@ -393,11 +339,11 @@ public final class ErrorPageWriter
                     printed = true;
                 }
             }
-            else if ("now".equals(ERROR_PARTS[i]))
+            else if ("now".equals(errorParts[i]))
             {
                 writer.write(DateFormat.getDateTimeInstance().format(now));
             }
-            else if ("tree".equals(ERROR_PARTS[i]))
+            else if ("tree".equals(errorParts[i]))
             {
                 if (view != null)
                 {
@@ -405,16 +351,16 @@ public final class ErrorPageWriter
                     _writeComponent(faces, writer, view, errorIds, true);
                 }
             }
-            else if ("vars".equals(ERROR_PARTS[i]))
+            else if ("vars".equals(errorParts[i]))
             {
                 _writeVariables(writer, faces, view);
             }
-            else if ("cause".equals(ERROR_PARTS[i]))
+            else if ("cause".equals(errorParts[i]))
             {
                 boolean printed = false;
                 Iterator<UIComponent> iterator = null;
                 if (components != null)
-                { 
+                {
                     iterator = components.iterator();
                 }
                 for (Throwable e : exs)
@@ -427,11 +373,9 @@ public final class ErrorPageWriter
                     if (iterator != null)
                     {
                         UIComponent uiComponent = iterator.next();
-                        if (uiComponent != null) {
+                        if (uiComponent != null)
+                        {
                             _writeComponent(faces, writer, uiComponent, null, /* writeChildren */false);
-                            //writer.write("<br/>");
-                            //writer.write(RendererUtils.getPathToComponent(uiComponent));
-                            //writer.write("<br/>");
                         }
                     }
                     printed = true;
@@ -439,7 +383,7 @@ public final class ErrorPageWriter
             }
             else
             {
-                writer.write(ERROR_PARTS[i]);
+                writer.write(errorParts[i]);
             }
         }
     }
@@ -455,42 +399,43 @@ public final class ErrorPageWriter
     {
         _init(faces);
         Date now = new Date();
-        for (int i = 0; i < DEBUG_PARTS.length; i++)
+        for (int i = 0; i < debugParts.length; i++)
         {
-            if ("message".equals(DEBUG_PARTS[i]))
+            if ("message".equals(debugParts[i]))
             {
                 writer.write(faces.getViewRoot().getViewId());
             }
-            else if ("now".equals(DEBUG_PARTS[i]))
+            else if ("now".equals(debugParts[i]))
             {
                 writer.write(DateFormat.getDateTimeInstance().format(now));
             }
-            else if ("tree".equals(DEBUG_PARTS[i]))
+            else if ("tree".equals(debugParts[i]))
             {
                 _writeComponent(faces, writer, faces.getViewRoot(), null, true);
             }
-            else if ("extendedtree".equals(DEBUG_PARTS[i]))
+            else if ("extendedtree".equals(debugParts[i]))
             {
                 _writeExtendedComponentTree(writer, faces);
             }
-            else if ("vars".equals(DEBUG_PARTS[i]))
+            else if ("vars".equals(debugParts[i]))
             {
                 _writeVariables(writer, faces, faces.getViewRoot());
             }
             else
             {
-                writer.write(DEBUG_PARTS[i]);
+                writer.write(debugParts[i]);
             }
         }
     }
-    
-    public static void handle(FacesContext facesContext, Collection<UIComponent> components, Throwable... exs) throws FacesException
+
+    public static void handle(FacesContext facesContext, Collection<UIComponent> components,
+                              Throwable... exs) throws FacesException
     {
         for (Throwable ex : exs)
         {
             _prepareExceptionStack(ex);
         }
-        
+
         if (!facesContext.getExternalContext().isResponseCommitted())
         {
             facesContext.getExternalContext().responseReset();
@@ -513,7 +458,7 @@ public final class ErrorPageWriter
         {
             facesContext.getExternalContext().setResponseStatus(responseStatus);
         }
-        
+
         // normal request --> html error page
         facesContext.getExternalContext().setResponseContentType("text/html");
         facesContext.getExternalContext().setResponseCharacterEncoding("UTF-8");
@@ -549,16 +494,16 @@ public final class ErrorPageWriter
     public static void handleThrowable(FacesContext facesContext, Throwable ex) throws FacesException
     {
         _prepareExceptionStack(ex);
-        
+
         boolean errorPageWritten = false;
-        
+
         // check if an error page is present in web.xml
         // if so, do not generate an error page
         //WebXml webXml = WebXml.getWebXml(facesContext.getExternalContext());
         //if (webXml.isErrorPagePresent())
         WebConfigProvider webConfigProvider = WebConfigProviderFactory.getWebConfigProviderFactory(
                 facesContext.getExternalContext()).getWebConfigProvider(facesContext.getExternalContext());
-        
+
         if(webConfigProvider.isErrorPagePresent(facesContext.getExternalContext()))
         {
             // save current view in the request map to access it on the error page
@@ -581,7 +526,7 @@ public final class ErrorPageWriter
                     {
                         httpResp.reset();
                         if (facesContext.getPartialViewContext().isAjaxRequest())
-                        {    
+                        {
                             // ajax request --> xml error page 
                             httpResp.setContentType("text/xml; charset=UTF-8");
                             try
@@ -609,7 +554,7 @@ public final class ErrorPageWriter
                             }
                         }
                         else
-                        {    
+                        {
                             // normal request --> html error page
                             httpResp.setContentType("text/html; charset=UTF-8");
                             try
@@ -623,16 +568,16 @@ public final class ErrorPageWriter
                             }
                         }
                         log.log(Level.SEVERE, "An exception occurred", ex);
-                        
+
                         // mark the response as complete
                         facesContext.responseComplete();
-                        
+
                         errorPageWritten = true;
                     }
                 }
             }
         }
-        
+
         // rethrow the throwable, if we did not write the error page
         if (!errorPageWritten)
         {
@@ -671,20 +616,20 @@ public final class ErrorPageWriter
 
     private static void _init(FacesContext context) throws IOException
     {
-        if (ERROR_PARTS == null)
+        if (errorParts == null)
         {
-            ERROR_PARTS = _splitTemplate(_getErrorTemplate(context));
+            errorParts = _splitTemplate(_getErrorTemplate(context));
         }
 
-        if (DEBUG_PARTS == null)
+        if (debugParts == null)
         {
-            DEBUG_PARTS = _splitTemplate(_getDebugTemplate(context));
+            debugParts = _splitTemplate(_getDebugTemplate(context));
         }
     }
 
     private static String[] _splitTemplate(String rsc) throws IOException
     {
-        InputStream is = ClassUtils.getContextClassLoader().getResourceAsStream(rsc);            
+        InputStream is = ClassUtils.getContextClassLoader().getResourceAsStream(rsc);
         if (is == null)
         {
             // try to get the resource from ExternalContext
@@ -694,7 +639,7 @@ public final class ErrorPageWriter
                 // fallback
                 is = ErrorPageWriter.class.getClassLoader().getResourceAsStream(rsc);
             }
-        }        
+        }
 
         if (is == null)
         {
@@ -714,25 +659,27 @@ public final class ErrorPageWriter
         String str = baos.toString();
         return str.split("@@");
     }
-    
+
     private static List<String> _getErrorId(Collection<UIComponent> components, Throwable... exs)
     {
         List<String> list = null;
         for (Throwable e : exs)
         {
             String message = e.getMessage();
-    
+
             if (message == null)
+            {
                 continue;
-    
+            }
+
             Pattern pattern = Pattern.compile(REGEX_PATTERN);
             Matcher matcher = pattern.matcher(message);
-    
+
             while (matcher.find())
             {
                 if (list == null)
                 {
-                    list = new ArrayList<String>(); 
+                    list = new ArrayList<String>();
                 }
                 list.add(matcher.group(1));
             }
@@ -744,7 +691,8 @@ public final class ErrorPageWriter
         else if (components != null)
         {
             list = new ArrayList<String>();
-            for (UIComponent uiComponent : components) {
+            for (UIComponent uiComponent : components)
+            {
                 if (uiComponent  != null)
                 {
                     list.add(uiComponent.getId());
@@ -763,7 +711,7 @@ public final class ErrorPageWriter
         pstr.close();
         writer.write(str.toString().replaceAll("<", TS));
     }
-    
+
     private static void _writeCause(Writer writer, Throwable ex) throws IOException
     {
         String msg = ex.getMessage();
@@ -771,8 +719,8 @@ public final class ErrorPageWriter
         if (ex instanceof ContextAware)
         {
             ContextAware caex = (ContextAware) ex;
-            contextAwareLocation = caex.getLocation().toString() + "    " +  
-                                   caex.getQName() + "=\"" + 
+            contextAwareLocation = caex.getLocation().toString() + "    " +
+                                   caex.getQName() + "=\"" +
                                    caex.getExpressionString() + "\"";
         }
         while (ex.getCause() != null)
@@ -781,12 +729,14 @@ public final class ErrorPageWriter
             if (ex instanceof ContextAware)
             {
                 ContextAware caex = (ContextAware) ex;
-                contextAwareLocation = caex.getLocation().toString() + "    " +  
-                                       caex.getQName() + "=\"" + 
+                contextAwareLocation = caex.getLocation().toString() + "    " +
+                                       caex.getQName() + "=\"" +
                                        caex.getExpressionString() + "\"";
             }
             if (ex.getMessage() != null)
+            {
                 msg = ex.getMessage();
+            }
         }
 
         if (msg != null)
@@ -800,7 +750,7 @@ public final class ErrorPageWriter
         }
         StackTraceElement stackTraceElement = ex.getStackTrace()[0];
         writer.write("<br/> at " + stackTraceElement.toString());
-        
+
         if (contextAwareLocation != null)
         {
             writer.write("<br/> <br/>");
@@ -826,12 +776,13 @@ public final class ErrorPageWriter
         _writeVariables(writer, ctx.getApplicationMap(), "Application Attributes");
     }
 
-    private static void _writeVariables(Writer writer, Map<String, ? extends Object> vars, String caption) throws IOException
+    private static void _writeVariables(Writer writer, Map<String, ? extends Object> vars, String caption)
+            throws IOException
     {
         writer.write("<table><caption>");
         writer.write(caption);
-        writer
-              .write("</caption><thead><tr><th style=\"width: 10%; \">Name</th><th style=\"width: 90%; \">Value</th></tr></thead><tbody>");
+        writer.write("</caption><thead><tr><th style=\"width: 10%; \">Name</th>"
+                     + "<th style=\"width: 90%; \">Value</th></tr></thead><tbody>");
         boolean written = false;
         if (!vars.isEmpty())
         {
@@ -845,10 +796,14 @@ public final class ErrorPageWriter
                     writer.write(key.replaceAll("<", TS));
                     writer.write("</td><td>");
                     Object value = entry.getValue();
-                    // in some (very rare) situations value can be null or not null but with null toString() representation
-                    if (value != null && value.toString() != null) {
+                    // in some (very rare) situations value can be null or not null
+                    // but with null toString() representation
+                    if (value != null && value.toString() != null)
+                    {
                         writer.write(value.toString().replaceAll("<", TS));
-                    } else {
+                    }
+                    else
+                    {
                         writer.write("null");
                     }
                     writer.write("</td></tr>");
@@ -863,7 +818,8 @@ public final class ErrorPageWriter
         writer.write("</tbody></table>");
     }
 
-    private static void _writeComponent(FacesContext faces, Writer writer, UIComponent c, List<String> highlightId, boolean writeChildren) throws IOException
+    private static void _writeComponent(FacesContext faces, Writer writer, UIComponent c, List<String> highlightId,
+                                        boolean writeChildren) throws IOException
     {
         writer.write("<dl><dt");
         if (_isText(c))
@@ -937,55 +893,55 @@ public final class ErrorPageWriter
         }
         writer.write("</dl>");
     }
-    
+
     /**
      * Creates the Extended Component Tree via UIViewRoot.visitTree()
      * and ExtendedComponentTreeVisitCallback as VisitCallback.
-     * 
+     *
      * @param writer
      * @param facesContext
      * @throws IOException
      */
-    private static void _writeExtendedComponentTree(Writer writer, 
+    private static void _writeExtendedComponentTree(Writer writer,
             FacesContext facesContext) throws IOException
     {
         VisitContext visitContext = VisitContext.createVisitContext(
                 facesContext, null, EnumSet.of(VisitHint.SKIP_UNRENDERED));
         facesContext.getViewRoot().visitTree(visitContext, new ExtendedComponentTreeVisitCallback(writer));
     }
-    
+
     /**
      * The VisitCallback that is used to create the Extended Component Tree.
-     * 
+     *
      * @author Jakob Korherr
      */
     private static class ExtendedComponentTreeVisitCallback implements VisitCallback
     {
 
         private Writer _writer;
-        
+
         public ExtendedComponentTreeVisitCallback(Writer writer)
         {
             _writer = writer;
         }
-        
+
         @SuppressWarnings("unchecked")
         public VisitResult visit(VisitContext context, UIComponent target)
         {
             final Map<String, Object> requestMap = context.getFacesContext()
                     .getExternalContext().getRequestMap();
-            
+
             try
             {
                 if (!(target instanceof UIViewRoot))
                 {
                     _writer.write("<dd>");
                 }
-                
+
                 UIComponent parent = target.getParent();
                 boolean hasChildren = (target.getChildCount() > 0 || target.getFacets().size() > 0);
                 String facetName = _getFacetName(target);
-                
+
                 if (!(target instanceof UIColumn))
                 {
                     if (parent instanceof UIColumn
@@ -1009,10 +965,10 @@ public final class ErrorPageWriter
                         _writeStart(_writer, parent, true, false);
                         _writer.write("</dt><dd>");
                     }
-                    
+
                     if (facetName != null)
                     {
-                        _writer.write("<span>" + facetName + "</span>"); 
+                        _writer.write("<span>" + facetName + "</span>");
                         _incrementVisitedFacetCount(parent);
                     }
                     _writer.write("<dl><dt");
@@ -1021,7 +977,7 @@ public final class ErrorPageWriter
                         _writer.write(" class=\"uicText\"");
                     }
                     _writer.write(">");
-                    
+
                     Map<String, List<Object[]>> debugInfos = null;
                     // is the target a EditableValueHolder component?
                     // If so, debug infos from DebugPhaseListener should be available
@@ -1031,7 +987,7 @@ public final class ErrorPageWriter
                         debugInfos = (Map<String, List<Object[]>>) requestMap
                                 .get(DEBUG_INFO_KEY + target.getClientId());
                     }
-                    
+
                     // Get the component's renderer.
                     // Note that getRenderer(FacesContext context) is definded in UIComponent,
                     // but it is protected, so we have to use reflection!
@@ -1048,18 +1004,18 @@ public final class ErrorPageWriter
                     {
                         // nothing - do not output renderer information
                     }
-                    
+
                     // write the component start
                     _writeStart(_writer, target, (hasChildren || debugInfos != null || renderer != null), false);
                     _writer.write("</dt>");
-                    
+
                     if (renderer != null)
                     {
                         // write renderer info
                         _writer.write("<div class=\"renderer\">Rendered by ");
                         _writer.write(renderer.getClass().getCanonicalName());
                         _writer.write("</div>");
-                        
+
                         if (!hasChildren && debugInfos == null)
                         {
                             // close the component
@@ -1068,7 +1024,7 @@ public final class ErrorPageWriter
                             _writer.write("</dt>");
                         }
                     }
-                        
+
                     if (debugInfos != null)
                     {
                         final String fieldid = target.getClientId() + "_lifecycle";
@@ -1083,7 +1039,7 @@ public final class ErrorPageWriter
                         _writer.write("<div id=\"");
                         _writer.write(fieldid);
                         _writer.write("\" class=\"lifecycle_values\">");
-                        
+
                         // process any available debug info
                         for (Map.Entry<String, List<Object[]>> entry : debugInfos.entrySet())
                         {
@@ -1098,7 +1054,7 @@ public final class ErrorPageWriter
                                 //     - 1: old value
                                 //     - 2: new value
                                 //     - 3: StackTraceElement List
-                                
+
                                 // oldValue and newValue could be null
                                 String oldValue = debugInfo[1] == null ? "null" : debugInfo[1].toString();
                                 String newValue = debugInfo[2] == null ? "null" : debugInfo[2].toString();
@@ -1110,7 +1066,7 @@ public final class ErrorPageWriter
                                 _writer.write(newValue);
                                 _writer.write("</b> in Phase ");
                                 _writer.write(debugInfo[0].toString());
-                                
+
                                 // check if a call stack is available
                                 if (debugInfo[3] != null)
                                 {
@@ -1127,7 +1083,7 @@ public final class ErrorPageWriter
                                     _writer.write(stackTraceId);
                                     _writer.write("\" class=\"stacktrace_values\">");
                                     _writer.write("<ul>");
-                                    for (StackTraceElement stackTraceElement 
+                                    for (StackTraceElement stackTraceElement
                                             : (List<StackTraceElement>) debugInfo[3])
                                     {
                                         _writer.write("<li>");
@@ -1136,20 +1092,20 @@ public final class ErrorPageWriter
                                     }
                                     _writer.write("</ul></div></div>");
                                 }
-                                
+
                                 _writer.write("</li>");
-                                
+
                                 i++;
                             }
                             _writer.write("</ol>");
                         }
-                        
+
                         _writer.write("</div></div>");
-                        
+
                         // now remove the debug info from the request map, 
                         // so that it does not appear in the scope values of the debug page 
                         requestMap.remove(DEBUG_INFO_KEY + target.getClientId());
-                        
+
                         if (!hasChildren)
                         {
                             // close the component
@@ -1159,21 +1115,21 @@ public final class ErrorPageWriter
                         }
                     }
                 }
-                
+
                 if (!hasChildren)
                 {
                     _writer.write("</dl>");
-                    
-                    while (parent != null 
-                            && ((parent.getChildCount()>0 && parent.getChildren().get(parent.getChildCount() - 1) == target)
-                                    || (parent.getFacetCount() != 0 
+
+                    while (parent != null &&
+                           ((parent.getChildCount()>0 && parent.getChildren().get(parent.getChildCount()-1) == target)
+                                    || (parent.getFacetCount() != 0
                                             && _getVisitedFacetCount(parent) == parent.getFacetCount())))
                     {
                         // target is last child of parent or the "last" facet
-                        
+
                         // remove the visited facet count from the attribute map
                         _removeVisitedFacetCount(parent);
-                        
+
                         // check for componentes that visit their children multiple times
                         if (parent instanceof UIData)
                         {
@@ -1193,18 +1149,18 @@ public final class ErrorPageWriter
                                 break;
                             }
                         }
-                        
+
                         _writer.write("</dd><dt>");
                         _writeEnd(_writer, parent);
                         _writer.write("</dt></dl>");
-                        
+
                         if (!(parent instanceof UIViewRoot))
                         {
                             _writer.write("</dd>");
                         }
-                        
+
                         target = parent;
-                        parent = target.getParent(); 
+                        parent = target.getParent();
                     }
                 }
             }
@@ -1212,12 +1168,12 @@ public final class ErrorPageWriter
             {
                 throw new FacesException(ioe);
             }
-            
+
             return VisitResult.ACCEPT;
         }
-        
+
     }
-    
+
     private static boolean _isFirstUIColumn(UIComponent uidata, UIColumn uicolumn)
     {
         for (int i = 0, childCount = uidata.getChildCount(); i < childCount; i++)
@@ -1230,7 +1186,7 @@ public final class ErrorPageWriter
         }
         return false;
     }
-    
+
     private static String _getFacetName(UIComponent component)
     {
         UIComponent parent = component.getParent();
@@ -1249,7 +1205,7 @@ public final class ErrorPageWriter
         }
         return null;
     }
-    
+
     private static int _getVisitedFacetCount(UIComponent component)
     {
         Integer count = visitedFacetCount.get(component);
@@ -1259,12 +1215,12 @@ public final class ErrorPageWriter
         }
         return 0;
     }
-    
+
     private static void _incrementVisitedFacetCount(UIComponent component)
     {
         visitedFacetCount.put(component, _getVisitedFacetCount(component) + 1);
     }
-    
+
     private static void _removeVisitedFacetCount(UIComponent component)
     {
         visitedFacetCount.remove(component);
@@ -1293,7 +1249,8 @@ public final class ErrorPageWriter
             String str = null;
             for (int i = 0; i < pd.length; i++)
             {
-                if ((pd[i].getWriteMethod() != null || Arrays.binarySearch(ALWAYS_WRITE, pd[i].getName()) > -1) && Arrays.binarySearch(IGNORE, pd[i].getName()) < 0)
+                if ((pd[i].getWriteMethod() != null || Arrays.binarySearch(ALWAYS_WRITE, pd[i].getName()) > -1)
+                    && Arrays.binarySearch(IGNORE, pd[i].getName()) < 0)
                 {
                     m = pd[i].getReadMethod();
                     try
@@ -1302,7 +1259,12 @@ public final class ErrorPageWriter
                         valueExpression = c.getValueExpression(pd[i].getName());
                         if (valueExpressionValues && valueExpression != null)
                         {
-                            _writeAttribute(writer, pd[i].getName(), valueExpression.getExpressionString());
+                            String expressionString = valueExpression.getExpressionString();
+                            if (null == expressionString)
+                            {
+                                expressionString = "";
+                            }
+                            _writeAttribute(writer, pd[i].getName(), expressionString);
                         }
                         else
                         {
@@ -1329,7 +1291,7 @@ public final class ErrorPageWriter
                                 {
                                     str = v.toString();
                                 }
-                                
+
                                 _writeAttribute(writer, pd[i].getName(), str);
                             }
                         }
@@ -1346,7 +1308,7 @@ public final class ErrorPageWriter
             {
                 _writeAttribute(writer, "binding", binding.getExpressionString());
             }
-            
+
             // write the location
             String location = _getComponentLocation(c);
             if (location != null)
@@ -1359,7 +1321,7 @@ public final class ErrorPageWriter
             // do nothing
         }
     }
-    
+
     private static void _writeAttribute(Writer writer, String name, String value) throws IOException
     {
         writer.write(" ");
@@ -1369,7 +1331,7 @@ public final class ErrorPageWriter
         writer.write("\"");
     }
 
-    private static void _writeStart(Writer writer, UIComponent c, 
+    private static void _writeStart(Writer writer, UIComponent c,
             boolean children, boolean valueExpressionValues) throws IOException
     {
         if (_isText(c))
@@ -1408,7 +1370,9 @@ public final class ErrorPageWriter
     {
 
         if (ex == null)
+        {
             return;
+        }
 
         // check for getRootCause and getCause-methods
         if (!_initCausePerReflection(ex, "getRootCause"))
@@ -1436,7 +1400,9 @@ public final class ErrorPageWriter
     private static boolean _initCauseIfAvailable(Throwable th, Throwable cause)
     {
         if (cause == null)
+        {
             return false;
+        }
 
         try
         {
@@ -1449,7 +1415,7 @@ public final class ErrorPageWriter
             return false;
         }
     }
-    
+
     /**
      * Gets the Location of the given UIComponent from its attribute map.
      * @param component

Added: myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ErrorPageWriterTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ErrorPageWriterTest.java?rev=1208626&view=auto
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ErrorPageWriterTest.java (added)
+++ myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ErrorPageWriterTest.java Wed Nov 30 18:17:57 2011
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.renderkit;
+
+import java.io.StringWriter;
+
+import javax.el.ValueExpression;
+import javax.faces.component.UIViewRoot;
+import javax.faces.component.html.HtmlOutputText;
+import javax.validation.constraints.AssertTrue;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.myfaces.renderkit.html.HtmlTextRenderer;
+import org.apache.myfaces.shared.util.StateUtils;
+import org.apache.myfaces.shared_impl.util.serial.DefaultSerialFactory;
+import org.apache.myfaces.test.base.AbstractJsfTestCase;
+import org.apache.myfaces.test.mock.MockRenderKitFactory;
+import org.apache.myfaces.test.mock.MockResponseWriter;
+
+/**
+ * @author Bruno Aranda (latest modification by $Author: struberg $)
+ * @version $Revision: 1188235 $ $Date: 2011-10-24 13:09:33 -0400 (Mon, 24 Oct 2011) $
+ */
+public class ErrorPageWriterTest extends AbstractJsfTestCase
+{
+    public static Test suite()
+    {
+        return new TestSuite(ErrorPageWriterTest.class); // needed in maven
+    }
+
+    private MockResponseWriter writer ;
+    private HtmlOutputText outputText;
+
+    public ErrorPageWriterTest(String name)
+    {
+        super(name);
+    }
+
+    public void setUp() throws Exception
+    {
+        super.setUp();
+
+        outputText = new HtmlOutputText();
+
+        writer = new MockResponseWriter(new StringWriter(), null, null);
+        facesContext.setResponseWriter(writer);
+        // TODO remove these two lines once myfaces-test goes alpha, see MYFACES-1155
+        facesContext.getViewRoot().setRenderKitId(MockRenderKitFactory.HTML_BASIC_RENDER_KIT);
+        facesContext.getRenderKit().addRenderer(
+                outputText.getFamily(),
+                outputText.getRendererType(),
+                new HtmlTextRenderer());
+        servletContext.setAttribute(StateUtils.SERIAL_FACTORY, new DefaultSerialFactory());
+
+        facesContext.getAttributes().put("org.apache.myfaces.RENDERED_JSF_JS", Boolean.TRUE);
+    }
+
+    public void tearDown() throws Exception
+    {
+        super.tearDown();
+        outputText = null;
+        writer = null;
+    }
+
+    public void testValueExpressionGetExpressionStringReturnsNull()
+    {
+        //See MYFACES-3413 for details
+        UIViewRoot root = facesContext.getViewRoot();
+//        UIForm form = new UIForm();
+//        form.setId("formId");
+//        
+//        form.getChildren().add(inputText);
+        root.getChildren().add(outputText);
+
+        ValueExpression ve = new NullReturningGetExpressionStringValueExpression();
+        
+        outputText.setValueExpression("rendered", ve);
+        String id = "testValueExpressionGetExpressionStringReturnsNullOutputComponent";
+        outputText.setId(id);
+        try 
+        {
+            StringWriter w = new StringWriter();
+            Throwable t = new Throwable("Placeholder throwable");
+            ErrorPageWriter.debugHtml(w, facesContext, t);
+            String output = w.toString();
+            int indexOfOutputComponentId = output.indexOf(id);
+            String surroundingText = "output component not found.";
+            if (-1 != indexOfOutputComponentId) {
+                surroundingText = output.substring(Math.max(0, indexOfOutputComponentId - 20), Math.min(output.length(), indexOfOutputComponentId + 280));
+            }
+            int indexOfHasRenderedAttribute = output.indexOf("rendered=\"\"");
+            boolean hasRenderedAttribute = (-1 != indexOfHasRenderedAttribute);
+            assertTrue("rendered attribute wasn't written correctly: " + surroundingText, hasRenderedAttribute);
+        }
+        catch (Exception e)
+        {
+            fail(e.getMessage());
+        }
+    }
+    
+}

Propchange: myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ErrorPageWriterTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/NullReturningGetExpressionStringValueExpression.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/NullReturningGetExpressionStringValueExpression.java?rev=1208626&view=auto
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/NullReturningGetExpressionStringValueExpression.java (added)
+++ myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/NullReturningGetExpressionStringValueExpression.java Wed Nov 30 18:17:57 2011
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.renderkit;
+import java.io.Serializable;
+
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.PropertyNotFoundException;
+import javax.el.PropertyNotWritableException;
+import javax.el.ValueExpression;
+
+public class NullReturningGetExpressionStringValueExpression extends ValueExpression implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public String getExpressionString() {
+            return null;
+        }
+
+        @Override
+        public boolean isReadOnly(ELContext arg0) {
+            return true;
+        }
+
+        @Override
+        public Class<?> getExpectedType() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public Class<?> getType(ELContext arg0)
+                throws NullPointerException, PropertyNotFoundException,
+                ELException {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public Object getValue(ELContext arg0) throws NullPointerException,
+                PropertyNotFoundException, ELException {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public void setValue(ELContext arg0, Object arg1)
+                throws NullPointerException, PropertyNotFoundException,
+                PropertyNotWritableException, ELException {
+            // TODO Auto-generated method stub
+            
+        }
+
+        @Override
+        public boolean equals(Object arg0) {
+            // TODO Auto-generated method stub
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            // TODO Auto-generated method stub
+            return 0;
+        }
+
+        @Override
+        public boolean isLiteralText() {
+            // TODO Auto-generated method stub
+            return false;
+        }
+    }
+

Propchange: myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/NullReturningGetExpressionStringValueExpression.java
------------------------------------------------------------------------------
    svn:eol-style = native