6 Replies Latest reply on Sep 20, 2009 12:43 AM by egoosen

    Generic DAO Pattern with SMPC

    egoosen

      Hi,


      I'm trying to implement the Generic DAO Pattern in my Seam application, but its not working.


      I'm getting a ClassCastException in BaseJPADAO constructor:


      public abstract class BaseJPADAO<T extends BaseEntity, PK extends Serializable> implements BaseDAO<T, PK> {
      
           @In
           EntityManager entityManager;
      
           private Class<T> type = null;
      
           public BaseJPADAO() {
                this.type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
           }




      @Name("tblUserDAO")
      @AutoCreate
      public class TblUserJPADAO extends BaseJPADAO<TblUser, Integer> implements TblUserDAO {
      
           public TblUser findTblUserByUsernamePassword(String username,
                     String password) {
                Map<String,String> parameters = new HashMap<String,String>();
                parameters.put("username",username);
                parameters.put("password",password);
                return findRecordByName("findTblUserByUsernamePassword", parameters);
           }
      
      }




      @Name("authenticator")
      public class Authenticator {
           @Logger
           Log log;
      
           @In
           Identity identity;
           @In
           Credentials credentials;
      
           @In
           TblUserJPADAO tblUserDAO;
      
           @Out(required=false, scope=ScopeType.SESSION)
          TblUser currentUser;
      
           public boolean authenticate() {
                log.info("authenticating {0}", credentials.getUsername());
                try {
                     currentUser = tblUserDAO.findTblUserByUsernamePassword(
                               credentials.getUsername(),
                               credentials.getPassword());
      
                     identity.addRole(currentUser.getAuthGroup().getGroupName());
      
                     return true;
      
                } catch (NoResultException ex) {
                     FacesMessages.instance().add("Invalid username/password");
                     return false;
                }
           }
      }




      I've come across other users who are also experiencing similar issues while trying to implement the Generic DAO Pattern in Seam:


      Link 1


      Link 2


      Link 3


      Has anyone managed to get this working in Seam?


      jboss-seam-2.1.0.CR1


      jboss-4.2.3.GA


      apache-tomcat-6.0.14

        • 1. Re: Generic DAO Pattern with SMPC
          egoosen

          Further to my previous post, I placed a breakpoint in the BaseJPADAO and noticed that the constructor gets called twice. It throws the ClassCastException on the second call.


          Caused by: java.lang.ClassCastException: java.lang.Class
               at za.co.mymed.dao.jpa.BaseJPADAO.<init>(BaseJPADAO.java:28)
               at za.co.mymed.dao.jpa.TblUserJPADAO.<init>(TblUserJPADAO.java:17)
               at za.co.mymed.dao.jpa.TblUserJPADAO_$$_javassist_3.<init>(TblUserJPADAO_$$_javassist_3.java)
               at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
               at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
               at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
               at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
               at java.lang.Class.newInstance0(Class.java:350)
               at java.lang.Class.newInstance(Class.java:303)
               at org.jboss.seam.Component.wrap(Component.java:1424)
               at org.jboss.seam.Component.instantiateJavaBean(Component.java:1362)
               at org.jboss.seam.Component.instantiate(Component.java:1279)
               at org.jboss.seam.Component.newInstance(Component.java:2027)
               ... 97 more


          I'm stumped...would really appreciate some help on this.

          • 2. Re: Generic DAO Pattern with SMPC
            vladimir.kovalyuk

            Please post all BaseJPADAO.java to see what is in 28th line.

            • 3. Re: Generic DAO Pattern with SMPC
              dro_k

              Seam uses Javassist to create sub-class of all the Seam components at runtime. So what happens here, that the call



              this.type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];



              fails since it's being called on the subclass. What you need to do is replace it with a bit more complex logic like the following that I copy/pasted from org.jboss.seam.framework.Home class depending how you use these DAO components:


                 public Class<E> getEntityClass()
                 {
                    if (entityClass == null)
                    {
                       Type type = getClass().getGenericSuperclass();
                       if (type instanceof ParameterizedType)
                       {
                          ParameterizedType paramType = (ParameterizedType) type;
                          if (paramType.getActualTypeArguments().length == 2)
                          {
                             // likely dealing with -> new EntityHome<Person>().getEntityClass()
                             if (paramType.getActualTypeArguments()[1] instanceof TypeVariable)
                             {
                                throw new IllegalArgumentException("Could not guess entity class by reflection");
                             }
                             // likely dealing with -> new Home<EntityManager, Person>() { ... }.getEntityClass()
                             else
                             {
                                entityClass = (Class<E>) paramType.getActualTypeArguments()[1];
                             }
                          }
                          else
                          {
                             // likely dealing with -> new PersonHome().getEntityClass() where PersonHome extends EntityHome<Person>
                             entityClass = (Class<E>) paramType.getActualTypeArguments()[0];
                          }
                       }
                       else
                       {
                          throw new IllegalArgumentException("Could not guess entity class by reflection");
                       }
                    }
                    return entityClass;
                 }
              



              cheers,


              Drew

              • 4. Re: Generic DAO Pattern with SMPC
                egoosen

                Hi Vladimir,


                Line 28 of BaseJPADAO is the constructor:



                public BaseJPADAO() {
                     this.type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
                }


                • 5. Re: Generic DAO Pattern with SMPC
                  egoosen

                  Hi Drew,


                  I'm not sure if I'm doing this correctly, but I implemented your code as follows:



                  public BaseJPADAO() {
                       Type type = getClass().getGenericSuperclass();
                          if (type instanceof ParameterizedType) {
                             ParameterizedType paramType = (ParameterizedType) type;
                             if (paramType.getActualTypeArguments().length == 2) {
                                // likely dealing with -> new EntityHome<Person>().getEntityClass()
                                if (paramType.getActualTypeArguments()[1] instanceof TypeVariable){
                                     throw new IllegalArgumentException("Could not guess entity class by reflection");
                                } else {
                                     // likely dealing with -> new Home<EntityManager, Person>() { ... }.getEntityClass()
                                     entity = (Class<T>) paramType.getActualTypeArguments()[1];
                                }
                             } else {
                                // likely dealing with -> new PersonHome().getEntityClass() where PersonHome extends EntityHome<Person>
                                entity = (Class<T>) paramType.getActualTypeArguments()[0];
                             }
                          } else {
                               throw new IllegalArgumentException("Could not guess entity class by reflection");
                          }
                  }



                  IllegalArgumentException is getting thrown from last else statement.


                  The type is class za.co.mymed.dao.jpa.TblUserJPADAO, and not instance of ParameterizedType.


                  Still unable to get the entity.


                  Any other suggestions? :)

                  • 6. Re: Generic DAO Pattern with SMPC
                    egoosen

                    I decided to extend the EntityQuery class, so I needed the functionality above, that I wasn't able to get working earlier in the year.
                    I worked on it again today, and got it working with this code:




                    /**
                     * Get the class of the entity being managed.
                     * <br />
                     * If not explicitly specified, the generic type of implementation is used.
                     */
                    public Class<E> getEntityClass() {
                         if (entityClass == null)
                         {
                              Type type = getClass().getGenericSuperclass();
                    
                              if (type instanceof ParameterizedType)
                              {
                                   ParameterizedType paramType = (ParameterizedType) type;
                                   if (paramType.getActualTypeArguments().length == 2)
                                   {
                                        // likely dealing with -> new EntityHome<Person>().getEntityClass()
                                        if (paramType.getActualTypeArguments()[1] instanceof TypeVariable)
                                        {
                                             throw new IllegalArgumentException("Could not guess entity class by reflection");
                                        }
                                        // likely dealing with -> new Home<EntityManager, Person>() { ... }.getEntityClass()
                                        else
                                        {
                                             entityClass = (Class<E>) paramType.getActualTypeArguments()[1];
                                        }
                                   }
                                   else
                                   {
                                        // likely dealing with -> new PersonHome().getEntityClass() where PersonHome extends EntityHome<Person>
                                        entityClass = (Class<E>) paramType.getActualTypeArguments()[0];
                                   }
                              }
                              else
                              {
                                   type = getClass().getSuperclass().getGenericSuperclass();
                                   ParameterizedType paramType = (ParameterizedType) type;
                                   if (paramType.getActualTypeArguments().length == 2)
                                   {
                                        // likely dealing with -> new EntityHome<Person>().getEntityClass()
                                        if (paramType.getActualTypeArguments()[1] instanceof TypeVariable)
                                        {
                                             throw new IllegalArgumentException("Could not guess entity class by reflection");
                                        }
                                        // likely dealing with -> new Home<EntityManager, Person>() { ... }.getEntityClass()
                                        else
                                        {
                                             entityClass = (Class<E>) paramType.getActualTypeArguments()[1];
                                        }
                                   }
                                   else
                                   {
                                        // likely dealing with -> new PersonHome().getEntityClass() where PersonHome extends EntityHome<Person>
                                        entityClass = (Class<E>) paramType.getActualTypeArguments()[0];
                                   }
                              }
                         }
                         return entityClass;
                    }