6 Replies Latest reply on Dec 29, 2008 12:02 PM by Adam Warski

    ClassCastException: ... cannot be cast to com.bah.englink.ej

    Chris Simons Expert


      Adam, et. Al,

      I'd really appreciate your help here.

      I'm following the Seam-Envers demo source code to implement a similar approach to my project. At this point, I'm just trying to pull a list of revisions to a particular object. Perhaps I'm not understanding what exactly is returned from using versionsReader.createQuery()?

      I'm receiving ClassCastExceptions when pulling a list of Versions, but I'm not really understanding why.

      What I have done:
      - custom RevisionEntity and RevisionEntityListener
      - Versioned, for testing, just a single field on the UserProfile entity
      - attempting to pull a list of revisions for a specific object, in this case, UserProfile
      - validated that Envers is working, revisions are being stored properly for UserProfile
      - not working: pulling a list of revisions to UserProfile with key: -2

      My VersionEntity (my RevisionEntity) stores userId, timestamp, and fullName.

      In a working SFSB, I have a "getHistory()" method that I want to return a list of revisions (just the fields above, userId, timestamp, and fullName). When this list is empty, the page works. As soon as I make a revision and pull back a list of revisions, I get the ClassCastException. But why is Envers trying to pull the Version back as a UserProfile? Here is the getHistory() code:

      @Factory("history")
       public List<Version> getHistory()
       {
       if (history == null)
       {
       List versions = versionsReader.createQuery().forRevisionsOfEntity(UserProfile.class, false, false)
       .add(VersionsRestrictions.idEq(cvUser.getUserProfile().getId()))
       .addOrder(RevisionProperty.desc())
       .getResultList();
      
       for (Object versionDataObject : versions)
       {
       Object[] versionData = (Object[]) versionDataObject;
       history.add(new Version((VersionEntity)versionData[0]));
       }
      
       }
      
       return history;
       }


      In addition, because I'm following the Seam-Envers demo source code, I have a Version.java, though I don't really understand why it is needed since I already have a VersionEntity. Here is Version.java:

      package com.bah.englink.ejb.revision;

      public class Version
      {
      
       private VersionEntity version;
      
       public Version(VersionEntity version)
       {
       this.version = version;
       }
      
       public VersionEntity getVersion()
       {
       return version;
       }
      }


      Lastly, a snippet from my JSF page wherein I place a RF dataTable of revisions:

      <rich:dataTable
       id="revisions"
       var="version"
       value="#{userProfileManager.history}"
       border="1"
       rendered="true"
       rowClasses="oddRows, evenRows"
       sortMode="single">
       <rich:column>
       <f:facet name="header">
       <h:outputText value="Revision Type" />
       </f:facet>
       <h:outputText value="#{version.version.userId}"/>


      Again, I'm not sure I follow why I must have "version.version.userId".

      I'd really appreciate your help. I feel like I'm quite close to having Envers implemented in the way that I want - but I'm not quite there.

      Thanks.

        • 1. Re: ClassCastException: ... cannot be cast to com.bah.englin
          Adam Warski Master

          Hello,

          you are querying for changes in the "UserProfile" class, and instances of that class are returned as the first element of the array.

          The second element will be the revision entity instance corresponding to the revision - in your case, instance of VersionEntity.

          The first element of the array, will contain the entity, that has been changed in that revision - for example, a change of a field. The second contains the meta-data - revision number and timestamp, and, as I understand, in your case the id of the user, which made the changes (Though if the user modifies his own profile, than in your case the changed entity and the user entity in versions entity may be the same)

          I don't remember what's in the Seam demo source code, but there may be some unneeded code because of some old refactorings :)

          Adam

          • 2. Re: ClassCastException: ... cannot be cast to com.bah.englin
            Chris Simons Expert

            Thanks, Adam. I understand and this is the one area of the Seam-Envers demo that offered a different use case than what I am striving for. I'm going to use versionData[1] now and it seems like that might do the trick. Thanks again for your timely support.

            • 3. Re: ClassCastException: ... cannot be cast to com.bah.englin
              Chris Simons Expert

              Adam,

              Everything's working now. Sweet!

              One question...how would I pull back the "modType" from my VersionEntity? Would I need to store this in my VersionEntity and pull it back from this?

              For example, in my dataTable above, I'd like to also show the modType, such as:

              <rich:column>
              <f:facet name="header">
               Change
              </f:facet:
              <h:outputText value="#{version.version.modType.name}"/>
              </rich:column>



              Also, I elaborated upon my getHistory() method and made a stateless session bean to handle this straight to a JSF data table for any class. Is there something I could add to my revisions to grab the modType? Thanks!

              public List<Version> getRevisionList(String strCls, Long primaryKey)
               {
              
               VersionsReader reader = VersionsReaderFactory.get(entityManager);
              
               revisions = new ArrayList<Version>();
              
               try
               {
               // Get the list of revisions for this entity
               List versions = reader.createQuery().forRevisionsOfEntity(Class.forName(strCls), false, false)
               .add(VersionsRestrictions.idEq(primaryKey))
               .addOrder(RevisionProperty.desc())
               .getResultList();
              
               // Add the revisions to the version list using our custom revision entity
               for (Object versionDataObject : versions) {
               Object[] versionData = (Object[]) versionDataObject;
               revisions.add(new Version((VersionEntity) versionData[1]));
               }
              
               return revisions;
               }
               catch (ClassNotFoundException cnfe)
               {
               if (log.isDebugEnabled())
               log.warn("Could not find Class.forName for String: " + strCls);
               }
               catch (Exception e)
               {
               if (log.isDebugEnabled())
               {
               log.warn("Could not grab revisions for: " + strCls);
               log.info(e.getStackTrace().toString());
               log.info(e.getMessage().toString());
               }
               }
              
               return null;
               }


              • 4. Re: ClassCastException: ... cannot be cast to com.bah.englin
                Adam Warski Master

                Hello,

                the mod type - an value of the RevisionType enum - is the second element in the array. So try versionData[2] :)

                Adam

                • 5. Re: ClassCastException: ... cannot be cast to com.bah.englin
                  Chris Simons Expert


                  Perfect, thank you!

                  Can I just say that you have build a great add-on and I'm glad to see it getting included into Hibernate Core?

                  • 6. Re: ClassCastException: ... cannot be cast to com.bah.englin
                    Adam Warski Master

                    Thanks :)

                    Hope it will work good for you.

                    --
                    Adam