8 Replies Latest reply on Aug 29, 2008 11:37 PM by Julien Kronegg

    anybody hit this bug in seam

    Dean Hiller Expert

      I know my debug.xhtml page works on exceptions because we have code that if you login as special user, it throws a runtime exception AND it DID go to the debug.xhtml page.  I can also hit it directly


      BUT there is a certain bug in seam where my app hits a bug(and there is nothing in the logs for what I hit) and then the debug.xhtml says it can't be find.  My application exception that must be occuring(from hibernate I think as I am having problems there)...here is the exception saying debug.xhtml can't be found....(anyway to get at the hibernate exception that occurs before this...on a merge(company), I was getting classcast exceptions deep in hibernate code...like company should be a Long or something weird like that.....



      WARNING: phase(RENDER_RESPONSE 6,com.sun.faces.context.FacesContextImpl@115416d) threw exception: javax.el.ELException: /file:/D:/BBROOT/tomcat-6.0.16/webapps/dayce/WEB-INF/lib/jboss-seam-debug.jar!/META-INF/debug.xhtml: null /file:/D:/BBROOT/tomcat-6.0.16/webapps/dayce/WEB-INF/lib/jboss-seam-debug.jar!/META-INF/debug.xhtml: null
      com.sun.facelets.compiler.TextInstruction.write(TextInstruction.java:50)
      com.sun.facelets.compiler.UIInstructions.encodeBegin(UIInstructions.java:39)
      com.sun.facelets.compiler.UILeaf.encodeAll(UILeaf.java:149)
      com.sun.facelets.component.RepeatRenderer.encodeChildren(RepeatRenderer.java:50)
      com.sun.facelets.component.UIRepeat.process(UIRepeat.java:357)
      com.sun.facelets.component.UIRepeat.encodeChildren(UIRepeat.java:617)
      com.sun.facelets.tag.jsf.ComponentSupport.encodeRecursive(ComponentSupport.java:244)
      com.sun.facelets.tag.jsf.ComponentSupport.encodeRecursive(ComponentSupport.java:249)
      com.sun.facelets.tag.jsf.ComponentSupport.encodeRecursive(ComponentSupport.java:249)
      org.jboss.seam.debug.jsf.SeamDebugPhaseListener.beforePhase(SeamDebugPhaseListener.java:51)
      com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:222)
      com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:144)
      javax.faces.webapp.FacesServlet.service(FacesServlet.java:245)
      org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
      org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
      org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)
      org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
      org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
      org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
      org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
      org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
      org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:154)
      org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:260)
      org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:366)
      org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:493)
      org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56)
      org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
      org.jboss.seam.debug.hot.HotDeployFilter.doFilter(HotDeployFilter.java:68)
      org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
      org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
      org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
      org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
      org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
      org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
      org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
      org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
      org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
      org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
      org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
      org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
      java.lang.Thread.run(Unknown Source)
      
      


        • 1. Re: anybody hit this bug in seam
          Pete Muir Master

          I have seen problems like this before, but I thought I fixed it. Make sure you are running Seam 2.0.2. If so, post an issue in JIRA with a simple seam-gen based example that shows how to reproduce. Make sure there is no extra code in the example.

          • 2. Re: anybody hit this bug in seam
            Dean Hiller Expert

            unfortunately, this was a week ago...I checked and I am using version 2.1.0.A1(in manifest)  I can't remember what was going on.  I figured out the exception that was happening in hibernate and once that was fixed, didn't hit this problem again. It just seems there was not code around the commit of the transaction or something like that as that is when the debug page fails to work....when I get exception out of my app, it usually works fine, but I am not 100%sure.

            • 3. Re: anybody hit this bug in seam
              Julien Kronegg Novice

              The exception is swallowed in Sun's JSF RI implementation: the LifecycleImpl.phase method catch the exception and display the warning with message [lifecycle] phase (..., where ... is the whole block you copied in your post (including the stacktrace).
              The exception is raised in the org.jboss.seam.debug.jsf.SeamDebugPhaseListener.beforePhase.


              I think this is the main problem: the exception is raised in the debug page itself (its a classical exception in an exception problem).
              The second problem is that LifecycleImpl only display the exception and not its causes. In my case, the cause was:


              22:26:12,859 ERROR \[STDERR\] Caused by: java.lang.NullPointerException
              22:26:12,890 ERROR \[STDERR\]     at javax.el.BeanELResolver$BeanProperty.read(BeanELResolver.java:247)
              22:26:12,906 ERROR \[STDERR\]     at javax.el.BeanELResolver.getValue(BeanELResolver.java:60)
              22:26:12,937 ERROR \[STDERR\]     at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:53)
              22:26:12,953 ERROR \[STDERR\]     at com.sun.faces.el.FacesCompositeELResolver.getValue(FacesCompositeELResolver.java:64)
              22:26:12,984 ERROR \[STDERR\]     at org.jboss.el.parser.AstPropertySuffix.getValue(AstPropertySuffix.java:53)
              22:26:13,000 ERROR \[STDERR\]     at org.jboss.el.parser.AstValue.getValue(AstValue.java:67)
              22:26:13,031 ERROR \[STDERR\]     at org.jboss.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:186)
              22:26:13,046 ERROR \[STDERR\]     at com.sun.facelets.el.ELText$ELTextVariable.writeText(ELText.java:184)
              22:26:13,078 ERROR \[STDERR\]     at com.sun.facelets.el.ELText$ELTextComposite.writeText(ELText.java:108)
              22:26:13,093 ERROR \[STDERR\]     at com.sun.facelets.compiler.TextInstruction.write(TextInstruction.java:45)
              22:26:13,109 ERROR \[STDERR\]     ... 52 more
              



              I obtained the cause by using the following technique



              1. 1. getting the jsf-impl.jar version (see manifest.mf) and source code on https://javaserverfaces.dev.java.net/servlets/ProjectDocumentList?folderID=9134&expandFolder=9134&folderID=7515

              2. addng a e.printStackException() in the LifecycleImpl.phase catch block.

              3. recompile LifecycleImpl using javac -classpath ;jsf-api.jar;jsf-impl.jar;servlet-api.jar LifecycleImpl.java

              4. repack jsf-impl.jar using 7zpip and replace all version on the server



              Lets's inspect el-api.jar/javax.el.BeanELResolver from the stacktrace above. Based on the latest JEE javadoc, we can see that the BeanProperty.read() method does not exist. Thus, there a difference of version.


              The next steps:



              • get the latest version of el-api.jar (jar and source code) and replace the existing version to test if the NPE above still occur



              I hope it helped...

              • 4. Re: anybody hit this bug in seam
                Julien Kronegg Novice

                I took the el-jar.api and sources from java.net. It helps (the null error is no more there), but this is not perfect: I obtained the following stacktrace:


                23:54:46,859 WARN  \[lifecycle\] phase(RENDER_RESPONSE 6,com.sun.faces.context.FacesContextImpl@b30eb5) threw exception: javax.el.ELException: /file:/C:/Workspace/jboss-4.2.1.GA/server/default/deploy/networking20.ear/networking20.war/WEB-INF/lib/jboss-seam-debug.jar!/META-INF/debug.xhtml: The class 'org.hibernate.exception.GenericJDBCException' does not have a readable property 'message'. /file:/C:/Workspace/
                jboss-4.2.1.GA/server/default/deploy/networking20.ear/networking20.war/WEB-INF/lib/jboss-seam-debug.jar!/META-INF/debug.xhtml: The class 'org.hibernate.exception.GenericJDBCException' does not have a readable property 'message'.
                com.sun.facelets.compiler.TextInstruction.write(TextInstruction.java:48)
                com.sun.facelets.compiler.UIInstructions.encodeBegin(UIInstructions.java:39)
                com.sun.facelets.compiler.UILeaf.encodeAll(UILeaf.java:149)
                com.sun.facelets.component.RepeatRenderer.encodeChildren(RepeatRenderer.java:50)
                com.sun.facelets.component.UIRepeat.process(UIRepeat.java:357)
                com.sun.facelets.component.UIRepeat.encodeChildren(UIRepeat.java:617)
                com.sun.facelets.tag.jsf.ComponentSupport.encodeRecursive(ComponentSupport.java:244)
                com.sun.facelets.tag.jsf.ComponentSupport.encodeRecursive(ComponentSupport.java:249)
                com.sun.facelets.tag.jsf.ComponentSupport.encodeRecursive(ComponentSupport.java:249)
                org.jboss.seam.debug.jsf.SeamDebugPhaseListener.beforePhase(SeamDebugPhaseListener.java:51)
                com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:222)
                com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:144)
                javax.faces.webapp.FacesServlet.service(FacesServlet.java:245)
                org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
                ...
                



                The problem comes from the java.beans.Introspector which computes a PropertyDescriptor[] (shortly: a PropertyDescriptor contains the property name, and the get/set method names).
                If the class contains two methods with the same name, one without parameters (e.g. getMessage() and one with an integer parameter (e.g. getMessage(int)), the Introspector will only recognize the method with int parameter and will generate an IndexedPropertyDescriptor (which maps an array of indexed values, e.g. getMessage(10) will return the 10th message).


                The PropertyDescriptor has a getReadMethod() and a getWriteMethod().
                The IndexedPropertyDescriptor has these methods too, and also getIndexedReadMethod() and getIndexedWriteMethod()


                The stacktrace above says that GenericJDBCException has no writable property because it inherits from NestableRuntimeException which has the two following methods:



                • public String getMessage();

                • public String getMessage(int);



                Based on these methods, the Introspector generate for the message property: an IndexedPropertyDescriptor with indexedReadMethod=getMessage and readMethod=null
                Then, when the BeanELResolver (not displayed in the stacktrace above, but called by TextInstruction.write()) asks for the read method by using getReadMethod, which returns obviously null, so the exception is raised.
                This is particulary important because the HibernateException also inherits from NestableRuntimeException, so any Hibernate problem will crash the debug page.


                Below is the code example which shows the problem (try to comment out the getMessage(int) method)



                public class TestReadProp {
                
                     public static void main(String[] args) {
                          ELContext c = new ELContext() {
                               public ELResolver getELResolver() {return null;}
                               public FunctionMapper getFunctionMapper() {return null;     }
                               public VariableMapper getVariableMapper() {return null;}
                          };
                          
                          BeanELResolver b = new BeanELResolver();
                          A e = new A();
                          System.out.println(e.getMessage());
                          System.out.println(b.getValue(c, e, "message")); // should also display "foobar"
                     }
                }
                
                public class A {
                      public String getMessage() {
                          return "foobar";
                     }
                      
                     public String getMessage(int i) {
                          return ""+i;
                     }
                }
                



                I will now work a little bit on a solution, but either the javax.el.BeanELResolver or the java.beans.Introspector must be modified.
                At least, this is not a Seam problem...

                • 5. Re: anybody hit this bug in seam
                  Pete Muir Master

                  Please file your findings in JIRA, with instructions to reproduce, I would like to see if Seam can be more helpful at all...

                  • 6. Re: anybody hit this bug in seam
                    Julien Kronegg Novice

                    I didn't took the time to file a new bug report in JIRA yet (I need some time to reproduce the bug using a minimal example).


                    However, I managed to correct the problem of breaked Seam debug page. Below is a summary of my findings.


                    This bug has already been listed in Sun's JDK:




                    According to these bug reports, the problem comes from the java.beans specification which do not details how to process methods with the following signature:



                    • Object getObject()

                    • Object getObject(int)



                    In this case, and from what I understood (I did not read it), the java beans specification proposes to return only one getter and of course both are candidate, so the priority is not defined.
                    Based on the bug reports and on the java.beans.Introspector source code, I can say that getting the PropertyDescriptor[] has a lot of work, with plenty of special cases.
                    Thus, correcting the Introspector should be a lot of work too, because it would imply a lot of special case testing.


                    On the other side, by looking at the javax.el.BeanELResolver source code snippet below, you can see that the read method is invoked with zero parameters:


                            BeanProperty bp = getBeanProperty(context, base, property);
                            Method method = bp.getReadMethod();
                            
                         // <== insert the 'method' correction here
                              
                            if (method == null) {
                                throw new PropertyNotFoundException(
                                            ELUtil.getExceptionMessageString(context,
                                                "propertyNotReadable",
                                                new Object\[\] { base.getClass().getName(),
                                                               property.toString()}));
                            }
                    
                            Object value;
                            try {
                                value = method.invoke(base, new Object\[0\]);
                                context.setPropertyResolved(true);
                            } catch (ELException ex) {
                                throw ex;
                            } catch (InvocationTargetException ite) {
                                throw new ELException(ite.getCause());
                            } catch (Exception ex) {
                                throw new ELException(ex);
                            }
                    



                    Thus, the BeanELResolver should not obtain the read method from the Introspector which do not constrains to getters with zero parameters. Based on that, I corrected the BeanELResolver by using the following idea: since the programmer calls BeanELResolver.getValue(..) to get the bean value, this property should exist because the programmer nows what s/he do. So when the read method is null (variable 'method'), we try to get the get<property> or the is<property> by using the Class.getMethod(), restricted to the method with 0 arguments (the code below is inserted into the code above at the insertion point):


                            if (method==null) {
                                 // no method found => trust the programmer (a get<property>() should exist in <base>.class) => try to find it
                                 String capitalized_property = capitalize(property.toString());
                                  try {
                                       method = base.getClass().getMethod("get"+capitalized_property, new Class[0]);
                                       //System.out.println("trusting programmer part 1: looking for property  get"+capitalized_property+": "+method);
                                  } catch (Exception e1) {
                                       // do nothing (intentionally): we just try to recover an error, so no need to warn the user
                                       //e1.printStackTrace();
                                  }//end try
                                  if (method==null) {
                                       // method still not found => try to find "is<property>"
                                       try {
                                           method = base.getClass().getMethod("is"+capitalized_property, new Class[0]);
                                           //System.out.println("trusting programmer part 2: looking for property  is"+capitalized_property+": "+method);
                                      } catch (Exception e1) {
                                           // do nothing (intentionally): we just try to recover an error, so no need to warn the user
                                      }//end try
                              }//end if
                         }//end if
                    



                    When repackaged into el-api.jar and replaced in the project and server libs, the application now works as espected: the Seam debug page is displayed with the exception stacktrace.
                    The repackaged version of el-api.jar is available on my server (sources are included).


                    Of course, this may not be the optimal solution (I would probably be better to rewrite the BeanELResolver or even Introspector), but it works...


                    My next task is to create the minimal Seam project to reproduce the bug.