14 Replies Latest reply on Oct 18, 2007 3:33 PM by Paul Kossler

    coerceToType / javaassist error

    Damian Harvey Master

      I'm getting the following error on a few pages (using Seam 2.0.0.CR1):

      java.lang.IllegalArgumentException: Cannot convert com.locuslive.odyssey.entity.Groups@3960f3 of type class com.locuslive.odyssey.entity.Groups to class com.locuslive.odyssey.entity.Groups_$$_javassist_219
      

      My page fragment looks like this:
      <fieldset class="inputFieldset">
       <legend>#{messages['users.groups']}</legend>
       <div style="">
       <h:selectManyCheckbox layout="pageDirection" id="userGroups" value="#{adminMaintainUser.groups}">
       <s:selectItems value="#{adminMaintainUser.allGroups}" var="groups" label="${groups.groupName}" />
       <s:convertEntity/>
       </h:selectManyCheckbox>
       </div>
      </fieldset>
      

      My adminMaintainUser Bean includes the following methods:
      public List<Groups> getAllGroups() {
       //Get all possible groups for this company
       return entityManager.createQuery("select g from Groups AS g where g.companyByCompanyId = :company")
       .setParameter("company", userProfile.getUser().getCompany())
       .getResultList();
      
      }
      public List<Groups> getGroups() {
       //Populate the groups from the user entity before passing back to the page.
       return entityManager.createQuery("select ugl.groups from UserGroupList AS ugl WHERE ugl.user = :user")
       .setParameter("user", userHome.getInstance())
       .getResultList();
      }
      

      UserGroupList is an entity that contains both a User and a Group (ie. many-to-many join table).

      I've seen references to similar problems as this in the forum but they had issues that were fixed in Seam 1.2.1.GA.

      Can anyone point me in the right direction? Weirdly enough this used to work and I can't for the life of me see what has changed.

      Much appreciated.

      Thanks,

      Damian.



        • 1. Re: coerceToType / javaassist error
          Pete Muir Master

          Can you post the whole stack trace so we can see where the error is coming from.

          • 2. Re: coerceToType / javaassist error
            Damian Harvey Master

            Thanks Pete.

            14:23:31,971 INFO [AdminMaintainUser] Populating groups for User Doug. Currently 6
            14:23:31,982 INFO [AdminMaintainUser] User Id is 14
            14:23:32,002 ERROR [STDERR] Oct 9, 2007 2:23:32 PM com.sun.facelets.FaceletViewHandler handleRenderException
            SEVERE: Error Rendering View[/secure/admin/AdminMaintainUsers.xhtml]
            java.lang.IllegalArgumentException: Cannot convert com.locuslive.odyssey.entity.Groups@cc3e51 of type class com.locuslive.odyssey.entity.Groups to class com.locuslive.odyssey.entity.Groups_$$_javassist_548
             at org.jboss.el.lang.ELSupport.coerceToType(ELSupport.java:358)
             at org.jboss.el.ExpressionFactoryImpl.coerceToType(ExpressionFactoryImpl.java:46)
             at org.jboss.seam.el.SeamExpressionFactory.coerceToType(SeamExpressionFactory.java:70)
             at com.sun.faces.renderkit.html_basic.SelectManyCheckboxListRenderer.renderOption(SelectManyCheckboxListRenderer.java:275)
             at com.sun.faces.renderkit.html_basic.SelectManyCheckboxListRenderer.encodeEnd(SelectManyCheckboxListRenderer.java:146)
             at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:833)
             at javax.faces.component.UIComponent.encodeAll(UIComponent.java:896)
             at javax.faces.render.Renderer.encodeChildren(Renderer.java:137)
             at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:809)
             at javax.faces.component.UIComponent.encodeAll(UIComponent.java:886)
             at javax.faces.component.UIComponent.encodeAll(UIComponent.java:892)
             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.debug.hot.HotDeployFilter.doFilter(HotDeployFilter.java:68)
             at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
             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.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 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:156)
             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(Thread.java:613)
            


            • 3. Re: coerceToType / javaassist error
              Pete Muir Master

              If you can produce a runnable example showing this simply with no extra cruft, please report a jira issue so I can look :)

              • 4. Re: coerceToType / javaassist error
                Damian Harvey Master

                Pete,

                I've created a basic project illustrating this. I've attached it to the JIRA at http://jira.jboss.org/jira/browse/JBSEAM-2111.

                I've attached the project built with Seam 2.0.0.CR2 and it raises the error. I've also attached it built with Seam 1.2.1.GA and the error doesn't happen. This explains why it has just started happening for me as I've only recently upgraded.

                Thanks,

                Damian.

                • 5. Re: coerceToType / javaassist error
                  Paul Kossler Newbie

                  Many of us have come across this error. It seems to be caused by a flaw in the Directions for the JPA (which is Based on Hibernate) and Hibernate. They all assume you can use the proxy directly. You can't! The problem is direct use of a proxy object fails the GoF Pattern for proxies. Proxies REQUIRE an interface.

                  The issue is "Subject isNotA SubjectProxy".
                  Its not an EL issue. The AspectGenerated Proxy is following the GoF Proxy definition. The flaw is that everyone seems to be using the Proxy wrong. (Even his highness, Gavin King.) Read the books on the subject and the documentation and the forums. It is assumed that you can directly use the proxy asA subject; by definition this is an incorrect assumption.


                  Define a proper proxy-pattern it passes the "coerceToType" method from EL. Subj implements ISubj, Proxy implements ISubj. Therefore Subj isA ISubj and Proxy isA ISubj. Then when the coerceToType trys to make reconstitute the values in the ISubj it works because then the Proxy passes the critical isA test (Specifically isAssignableFrom())

                  ENOUGH TECH PAUL WHATS THE SOLUTION. (I know I say it my head)

                  QUICK AND DIRTY (REALLY DIRTY)
                  The quickest solution to this problem is to tell JPA or Hibernate to not use a Proxy. I know this causes serious issues: Less caching, dirty checks, lazy loading and all that lovely stuff.

                  PROPER SOLUTION:
                  The proper solution is "Design By Interface" and only reference the interface. Alas the Hibernate implementation has some mapping issues with this approach. (Cross mapping a storage solution via an interface can not be annotated currently, also the XML mappings seem to require double mapping of entities to the interfaces: note I am not sure on the latter)

                  These may be mitigated by defining the interface as the proxy

                  • 6. Re: coerceToType / javaassist error
                    Damian Harvey Master

                    Thanks Paul.

                    It sounds like you are saying that the problem is something fundamental with Hibernate??

                    I find it hard to believe that Seam/Hibernate doesn't handle this - it certainly did under Seam 1.2.1.GA. Can anyone offer a practical solution that fits in with Seam/Hibernate under Seam 2?

                    Thanks,

                    Damian.

                    • 7. Re: coerceToType / javaassist error
                      Paul Kossler Newbie

                      I am mainly saying that the implementation documentation leads people to the wrong conclusions. The example exercises all target direct use of the Proxy. This is incorrect for the GoF proxy pattern.

                      Seam handles some aspects of it for you; however, if you pass a Proxy AS A Subject to the View Layer through JSF; its lifecycle requires saving and reconstituting your objects. The coerceToType error occurs because the Proxy fails the to be converted to the Subject... because it is not one. This is correct. The problem is that you have to use a commonly implemented interface or tell the JPA/Hibernate/Ibatis et al. not to use the Auto-Proxy. Then it will build the actual Subject each time. Unfortunately, as I mentioned in my first posting on the topic, this seriously affects the caching paradigm.

                      Read GoF: Design Patterns. Proxy Pattern.
                      Use a common interface. (Eclipse can help you "Extract interfaces") Just read carefully into how to connect the interface to the mapped version. I mentioned that the annotation:
                      @org.hibernate.annotations.Proxy(proxyClass = myProxyInterface.class)
                      Does seem to function properly. I have not had the time to formally test this out. (on my todo list.)

                      :)

                      • 8. Re: coerceToType / javaassist error
                        Paul Kossler Newbie

                        Quick note: This occurs in all JSF implementations not just SEAM.( Which leverages JSF)

                        • 9. Re: coerceToType / javaassist error
                          Damian Harvey Master

                          Interesting but still doesn't explain why it worked in Seam 1.2.1.GA and 1.3.0.ALPHA. I'll try @Proxy if my problems persist.

                          Interestingly, I went back and looked at my old revisions and found a prior version under Seam 1.3.0.ALPHA had the same problem. A compare in SVN identified the culprit as being one of the following JARS:
                          jboss-el.jar
                          jboss-seam-gen.jar
                          jboss-seam-ioc.jar

                          When I rolled these back this issue didn't occur again under Seam 1.3.0.ALPHA. I can't get the same result under Seam 2.0.0.CR2 but will be working on the assumption that one of these jars is the cause.

                          Any suggestions?

                          Thanks,

                          Damian.

                          • 10. Re: coerceToType / javaassist error
                            Paul Kossler Newbie

                            Without knowing the details of the assumption directly in the EL implementation and the interpretation of the JSF lifecycle its hard to tell.

                            How does one solve the problem completely? Well, thats the million dollar question :)

                            I suggest writing a clean JUnit test scenario that proves the problem. Then, extend the diagnosis to the main problem at hand. Personally, I know how one can get lost in the details. JPA and Hibernate have done a fine job, though I think the core of the issue is the common misuse of the Proxy.

                            If it worked in one version and not the latest, you may have been able to slip past a crack in the implementation that is now fixed.

                            Good luck.

                            • 11. Re: coerceToType / javaassist error
                              Pete Muir Master

                              Remember JSF impls changed between AS 4.0.5 and 4.2. The problem arises from mapping your ManyToOne as lazy. Unfortunately I don't think @Proxy will help as you will still be trying to coerce to a proxy.

                              • 12. Re: coerceToType / javaassist error
                                Damian Harvey Master

                                Thanks Pete. Just tried changing the mapping to EAGER and it works fine. Much appreciated.



                                • 13. Re: coerceToType / javaassist error
                                  Pete Muir Master

                                  Or you can ommit the property entirely.

                                  I would like to get this fixed properly - however as it stands either JSF or EL needs to be aware of javassist proxies (I can't see another solution).

                                  • 14. Re: coerceToType / javaassist error
                                    Paul Kossler Newbie

                                    Pete:
                                    Using @Proxy pointed to an the common ISubject interface does work. I will try to send a test case soon.

                                    Turning off the proxy also works.

                                    I do not have time to go into detail; however, look at the use of natural keys for the links for ManyToOne mappings. ProHibernate3 talks about it. Though only some discussion. This way the lazy-load of an object into a map can use the "natural key"-"machine-key" as key-value. Then lazy loading can load the object iff it has been selected and another transaction to the server occurs and the natural key can be displayed in selectItems as a <String, PK>.