9 Replies Latest reply on Sep 29, 2007 7:01 AM by Pete Muir

    EntityQuery bug

    Ricardo Memoria Novice

      Hi all,

      I'm using SEAM 2.0.0 from the CVS and it seems to have the same problem since version 1.2.1.

      I have an EntityQuery object like that:

      @Name("localities")
      public class LocalitiesQuery extends EntityQuery {
       private static final long serialVersionUID = -4255032277168197004L;
      
       private String[] restrictions = {"l.region = #{localities.region}"};
      
       private Region region;
      
       public Region getRegion() {
       return region;
       }
      
       public void setRegion(Region region) {
       this.region = region;
       }
      
       @Override
       public String getEjbql() {
       return "from Locality l join fetch l.region";
       }
      
       @Override
       public List<String> getRestrictions() {
       return Arrays.asList(restrictions);
       }
      
       @Override
       protected String getCountEjbql() {
       return "select count(*) from Locality l";
       }
      
      }


      PROBLEM: If I try to read localities.resultCount with a restriction defined, I get the following error:


      javax.faces.FacesException: javax.el.ELException: /admin/localities.xhtml @37,119 rendered="#{localities.resultCount == 0}": Error reading 'resultCount' on type com.rmemoria.drugman.LocalitiesQuery_$$_javassist_5
       at javax.faces.component.UIComponentBase.isRendered(UIComponentBase.java:373)
       at javax.faces.component.UIComponent.encodeAll(UIComponent.java:880)
       at javax.faces.render.Renderer.encodeChildren(Renderer.java:137)
       at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:812)
       at javax.faces.component.UIComponent.encodeAll(UIComponent.java:886)
       at javax.faces.component.UIComponent.encodeAll(UIComponent.java:892)
       at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:577)
       at org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:108)
       at org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:216)
       at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:106)
       at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251)
       at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:144)
       at javax.faces.webapp.FacesServlet.service(FacesServlet.java:245)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
       at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)
       at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
       at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
       at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
       at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:44)
       at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
       at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:141)
       at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:281)
       at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:60)
       at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
       at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:58)
       at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
       at org.jboss.seam.debug.hot.HotDeployFilter.doFilter(HotDeployFilter.java:68)
       at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
       at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:150)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at com.rmemoria.utils.NoCacheFilter.doFilter(NoCacheFilter.java:40)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
       at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
       at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
       at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
       at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
       at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
       at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
       at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
       at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
       at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:241)
       at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
       at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:580)
       at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
       at java.lang.Thread.run(Unknown Source)
      Caused by: javax.el.ELException: /admin/localities.xhtml @37,119 rendered="#{localities.resultCount == 0}": Error reading 'resultCount' on type com.rmemoria.drugman.LocalitiesQuery_$$_javassist_5
       at com.sun.facelets.el.TagValueExpression.getValue(TagValueExpression.java:76)
       at javax.faces.component.UIComponentBase.isRendered(UIComponentBase.java:370)
       ... 52 more
      Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryParameterException: could not locate named parameter [el1]
       at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:176)
       at org.jboss.seam.framework.EntityQuery.setParameters(EntityQuery.java:180)
       at org.jboss.seam.framework.EntityQuery.createCountQuery(EntityQuery.java:169)
       at org.jboss.seam.framework.EntityQuery.initResultCount(EntityQuery.java:105)
       at org.jboss.seam.framework.EntityQuery.getResultCount(EntityQuery.java:97)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
       at java.lang.reflect.Method.invoke(Unknown Source)
       at org.jboss.seam.util.Reflections.invoke(Reflections.java:23)
       at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:31)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56)
       at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:31)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
       at org.jboss.seam.transaction.TransactionInterceptor$1.work(TransactionInterceptor.java:38)
       at org.jboss.seam.util.Work.workInTransaction(Work.java:39)
       at org.jboss.seam.transaction.TransactionInterceptor.aroundInvoke(TransactionInterceptor.java:32)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
       at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:42)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
       at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:106)
       at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:155)
       at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:91)
       at com.rmemoria.drugman.LocalitiesQuery_$$_javassist_5.getResultCount(LocalitiesQuery_$$_javassist_5.java)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
       at java.lang.reflect.Method.invoke(Unknown Source)
       at javax.el.BeanELResolver.getValue(BeanELResolver.java:62)
       at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:53)
       at com.sun.faces.el.FacesCompositeELResolver.getValue(FacesCompositeELResolver.java:64)
       at org.jboss.el.parser.AstPropertySuffix.getValue(AstPropertySuffix.java:53)
       at org.jboss.el.parser.AstValue.getValue(AstValue.java:67)
       at org.jboss.el.parser.AstEqual.getValue(AstEqual.java:21)
       at org.jboss.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:186)
       at com.sun.facelets.el.TagValueExpression.getValue(TagValueExpression.java:71)
       ... 53 more
      Caused by: org.hibernate.QueryParameterException: could not locate named parameter [el1]
       at org.hibernate.engine.query.ParameterMetadata.ge
      11:05:29,328 ERROR [STDERR] tNamedParameterDescriptor(ParameterMetadata.java:75)
       at org.hibernate.engine.query.ParameterMetadata.getNamedParameterExpectedType(ParameterMetadata.java:81)
       at org.hibernate.impl.AbstractQueryImpl.determineType(AbstractQueryImpl.java:413)
       at org.hibernate.impl.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:383)
       at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:171)
       ... 88 more


      Watching the source code, it seems the resultCount construction is different from the resultList construction. It doesn't consider the restrictions at a first parser, but tries to pass the parameters during query executing.

      Regards,
      Ricardo Memoria

        • 1. Re: EntityQuery bug
          Ricardo Memoria Novice

          Hi all,

          I've been debugging the SEAM source code and I found a solution I would like to share with you. It requires modification in the SEAM source code, but it fix the bug in EntityQuery.

          in org.jboss.seam.framework.Query:

          include this new method:

          protected String getCountEjbqlWithRestrictions() {
           String hql = getCountEjbql();
          
           StringBuilder builder = new StringBuilder().append(hql);
          
           for (int i = 0; i < getRestrictions().size(); i++) {
           Object parameterValue = getRestrictionParameters().get(i)
           .getValue();
           if (isRestrictionParameterSet(parameterValue)) {
           if (WHERE_PATTERN.matcher(builder).find()) {
           builder.append(" and ");
           } else {
           builder.append(" where ");
           }
           builder.append(parsedRestrictions.get(i));
           }
           }
           return builder.toString();
           }


          in org.jboss.seam.framework.EntityQuery:

          in method createCountQuery() (around line 167), change the line

          javax.persistence.Query query = getEntityManager().createQuery( getCountEjbql() );


          to this

          javax.persistence.Query query = getEntityManager().createQuery( getCountEjbqlWithRestrictions() );


          It would be nice if it were permanently implemented in the SEAM source code (or something similar to fix the present problem).

          Regards,
          Ricardo




          • 2. Re: EntityQuery bug
            Adrian Mitev Master

            Add this to JIRA

            • 3. Re: EntityQuery bug
              Ricardo Memoria Novice

              Another bug just found.

              The Refresh method doesn't update changes in the Ejbql property.

              My EntityQuery has a condition that can't be included as a restriction. It is:

              @Name("mdrCases")
              public class MdrCasesQuery extends EntityQuery {
              
              private boolean allCases;
              
              @Override
              public String getEjbql() {
               String cond = allCases? "": " where (c.endingTreatmentDate is null)";
              
               return "from MdrCase c".concat(cond);
              }


              Since it doesn't contain any EL expression, it can't be included as a restriction. So the condition is placed on the fly when the user clicks a button to refresh the page:

              <s:decorate template="/layout/edit.xhtml">
               <ui:define name="label">#{messages['patients.allcases']}:</ui:define>
               <h:selectBooleanCheckbox value="#{mdrCases.allCases}"></h:selectBooleanCheckbox>
               </s:decorate>
              
               <h:commandButton action="#{mdrCases.refresh}" value="#{messages['form.search']}" styleClass="button" />
              


              The problem is that after the refresh method is called the Ejbql is not rebuild.

              I saw that in Query.refresh method, if I make a change like:

              public void refresh()
               {
               clearDataModel();
              
               // INCLUDE THIS LINE HERE
               parsedEjbql = null;
               }


              recompile and regenerate SEAM, it works just fine.


              • 4. Re: EntityQuery bug
                Ricardo Memoria Novice

                Ok,

                Added to JIRA

                • 5. Re: EntityQuery bug
                  Pete Muir Master

                  To continue the discussion from JIRA. The issue is you are addressing the wrong problem. You shouldn't need to override the countEjbql. The EntityQuery should be able to cope with that query (the related issue I created)

                  If you want to be able to do override the countEjbql, please add a feature request to JIRA (this does involve altering the api of the query classes).

                  • 6. Re: EntityQuery bug
                    Pete Muir Master

                    For the second issue (JBSEAM-1916) you should do something like this

                    @Name("mdrCases")
                    public class MdrCasesQuery extends EntityQuery {
                    
                     private boolean allCases;
                    
                     public void executeSearch() {
                     String ejbql = "from MdrCase c".concat(allCases? "": " where (c.endingTreatmentDate is null)");
                     super.setEjbql(ejbql);
                     }
                    }


                    <h:commandButton action="#{mdrCases.executeSearch}" value="Search" />


                    Why? Well parsing the ejbql is a reasonably expensive operation so to save some cycles you have to explicitly tell the Query that the ejbql has changed. This reserves the refresh method for updating the result based on changed restrictions/changed data.

                    I'm going to document this.

                    • 7. Re: EntityQuery bug
                      Pete Muir Master

                      Added javadoc to Query and EntityQuery making the contract of refresh explicit.

                      • 8. Re: EntityQuery bug
                        Ricardo Memoria Novice

                        Hi Pete,

                        Thanks for the reply...

                        Ok... The JBSEAM-1916 is done for me!

                        But the reason why I had to override the countEjbql() is because of a problem getting the resultCount() when I declare an EJBQL with "join fetch" in there.

                        for example: If I declare a query like that:

                        "from User u join fecth u.department"

                        EntityQuery generates an exception when I call getResultCount().

                        So I had to override countEjbql().

                        Any idea how to workaround this problem??

                        Thanks,
                        Ricardo

                        • 9. Re: EntityQuery bug
                          Pete Muir Master

                          http://jira.jboss.com/jira/browse/JBSEAM-1986

                          No, no idea how to workaround the problem for now, except what you are doing with a custom getResultCount()