1 2 Previous Next 18 Replies Latest reply on Sep 25, 2007 1:24 PM by mustaghattack

    Further extending an EntityHome

    damianharvey

      I have a BookingHome class that extends EntityHome. I now have to support several different types of Booking with slightly different logic. The obvious (and lazy) choice is to extend my BookingHome. For example:

      public class BulkBookingHome extends BookingHome {

      However when I try to do this it fails with the following error:
      Could not guess entity class by reflection

      This is from the org.jboss.seam.framework.Home class and I understand that it is caused by my class not being an instance of ParameterizedType (ie. BookingHome doesn't have a generic type).

      Is it possible to extend my own EntityHome classes? Can anyone suggest a solution? My intention is to not have to duplicate the logic that exists in the base BookingHome and ideally not to have to pull all of this logic out into separate Beans.

      I suspect that I'm just being a bit thick here....

      Thanks,

      Damian.

        • 1. Re: Further extending an EntityHome
          matt.drees

          Well, you could manually specify the entity class, eg

          @Override
          public Class<Booking> getEntityClass() {
           return Booking.class;
          }
          


          Or maybe you could do something like
          ...
           getClass.getSuperclass().getGenericSuperclass()
          ...(then same as in Home.java)
          

          if you don't want to hardcode it.

          • 2. Re: Further extending an EntityHome
            wise_guybg

            Have you not put different @Name annotations?

            Where exactly do you get the error?

            • 3. Re: Further extending an EntityHome
              damianharvey

              @Matt: I'll try that and let you know. Much appreciated.

              @Wise_guy: As mentioned the error is in the Home class. There is an explicit check that the parent class is parameterized with a generic type. @Name annotations are different as they are to be ued on different pages.

              Thanks,

              Damian.

              • 4. Re: Further extending an EntityHome
                damianharvey

                Bingo. Cheers Matt. Worked a treat. Your first suggestion worked first time (always nice).

                Does anyone know what behaviour that the block of code in the Home object is trying to avoid? ie: why not just take the class rather than throw the exception?

                Thanks,

                Damian.

                • 5. Re: Further extending an EntityHome
                  matt.drees

                   

                  "damianharvey" wrote:
                  Bingo. Cheers Matt. Worked a treat. Your first suggestion worked first time (always nice).

                  Cool

                  "damianharvey" wrote:

                  Does anyone know what behaviour that the block of code in the Home object is trying to avoid? ie: why not just take the class rather than throw the exception?

                  I think perhaps you misread that code. I'll post it here for reference:
                   public Class<E> getEntityClass()
                   {
                   if (entityClass==null)
                   {
                   Type type = getClass().getGenericSuperclass();
                   if (type instanceof ParameterizedType)
                   {
                   ParameterizedType paramType = (ParameterizedType) type;
                   entityClass = (Class<E>) paramType.getActualTypeArguments()[0];
                   }
                   else
                   {
                   throw new IllegalArgumentException("Could not guess entity class by reflection");
                   }
                   }
                   return entityClass;
                   }
                  


                  EntityHome needs to know what your entity's class is, so that it can create a new instance when needed. What it does is check to see if you've set an entity class (which is usually, I imagine, only done if this Home was created by xml in components.xml). If you haven't, it tries to guess the class by looking at the type parameter of the home instance's superclass.

                  In your case, the superclass wasn't EntityHome, but BookingHome, which has no type parameter. So, it couldn't get the class and threw an exception.

                  Make sense?

                  • 6. Re: Further extending an EntityHome
                    damianharvey

                    Had to add a line to the suggested code otherwise a NPE was thrown on persist:

                    @Override
                    public Class<Booking> getEntityClass() {
                     super.setEntityClass(Booking.class);
                     return Booking.class;
                    }

                    Cheers,

                    Damian.


                    • 7. Re: Further extending an EntityHome
                      mustaghattack

                      You may have to parameterize your BookingHome : try

                      public class BookingHome< B extends Booking > extends EntityHome< B > {
                      

                      and then

                      public class BulkBookingHome extends BookingHome<BulkBooking> {
                      


                      • 8. Re: Further extending an EntityHome
                        damianharvey

                        Thanks Mushtag but it's working fine with Matt's solution. Also BulkBooking isn't an Entity. BulkBookingHome is just a way of creating a Booking entity using some different logic.

                        Cheers,

                        Damian.

                        • 9. Re: Further extending an EntityHome
                          pmuir

                          Damian, please create a JIRA issue with the NPE in it and a link to this topic. We need to fix it.

                          • 10. Re: Further extending an EntityHome
                            damianharvey

                            Pete,

                            I don't think it's an issue. The NPE was only caused by the fact that I had overriden getEntityClass() but hadn't set the value of the entityClass field.

                            Cheers,

                            Damian.

                            • 11. Re: Further extending an EntityHome
                              mustaghattack

                              Hi, about the EntityHome class I think it would be better to just pass the entity class as a parameter for the constructor, or at least to have a parameterized constructor.
                              I've done a quick performance test to see the reflection overhead :
                              with a Sun 1.6 JVM it's > 30.

                              package test.java;
                              
                              import java.lang.reflect.ParameterizedType;
                              import java.lang.reflect.Type;
                              
                              public class GuessParameterizePerformanceTest {
                               public static class GuessParam< E > {
                               private Class< E > entityClass;
                              
                               public GuessParam() {
                               getEntityClass();
                               }
                              
                               public Class<E> getEntityClass()
                               {
                               if (entityClass==null)
                               {
                               Type type = getClass().getGenericSuperclass();
                               if (type instanceof ParameterizedType)
                               {
                               ParameterizedType paramType = (ParameterizedType) type;
                               entityClass = (Class<E>) paramType.getActualTypeArguments()[0];
                               }
                               else
                               {
                               throw new IllegalArgumentException("Could not guess entity class by reflection");
                               }
                               }
                               return entityClass;
                               }
                               }
                              
                               public static class DontGuessParam< E > {
                               private Class< E > entityClass;
                              
                               public DontGuessParam( Class< E > cls ) {
                               this.entityClass = cls;
                               getEntityClass();
                               }
                              
                               public Class< E > getEntityClass() {
                               return entityClass;
                               }
                               }
                              
                               public static class GuessParamChild extends GuessParam< String > {
                               }
                              
                               public static class DontGuessParamChild extends DontGuessParam< String > {
                               public DontGuessParamChild() {
                               super( String.class );
                               }
                               }
                              
                               public static void main(String[] args) {
                               float avgGuess = 0, avgDontGuess = 0;
                               float nbLoop = 5, nbInstanciation = 1000000;
                               long time;
                              
                               for( long i = 0; i < nbLoop; i ++ ) {
                               time = System.currentTimeMillis();
                               for( long j = 0; j < nbInstanciation; j ++ ) {
                               GuessParamChild guess = new GuessParamChild();
                               }
                               avgGuess += System.currentTimeMillis() - time;
                              
                               time = System.currentTimeMillis();
                               for( long j = 0; j < nbInstanciation; j ++ ) {
                               DontGuessParamChild dontGuess = new DontGuessParamChild();
                               }
                               avgDontGuess += System.currentTimeMillis() - time;
                               }
                              
                               System.out.println("avgGuess = " + (avgGuess / nbLoop));
                               System.out.println("avgDontGuess = " + (avgDontGuess / nbLoop));
                               System.out.println( "Guess overhead : " + ( avgGuess - avgDontGuess ) / avgDontGuess );
                               }
                              }
                              


                              • 12. Re: Further extending an EntityHome
                                matt.drees

                                 

                                "damianharvey" wrote:
                                I don't think it's an issue. The NPE was only caused by the fact that I had overriden getEntityClass() but hadn't set the value of the entityClass field.


                                Actually, I agree with Pete. If the contract of EntityHome requires getEntityClass() to be overridable (and it is, from what I gather), then it should always reference the getter, not the field.

                                • 13. Re: Further extending an EntityHome
                                  matt.drees

                                   

                                  "mustaghattack" wrote:
                                  Hi, about the EntityHome class I think it would be better to just pass the entity class as a parameter for the constructor, or at least to have a parameterized constructor.


                                  Seam instantiates (javabean) components with a no-arg constructor, so this won't help, unless you yourself instantiate an entityHome using "new", which you shouldn't ever be doing.

                                  • 14. Re: Further extending an EntityHome
                                    damianharvey

                                    Fair call Matt. I can see your point. It's a resonably trivial fix as only updatedMessage(), deletedMessage() and createdMessage() refer to entityClass rather than getEntityClass.

                                    http://jira.jboss.org/jira/browse/JBSEAM-1969

                                    Cheers,

                                    Damian.

                                    1 2 Previous Next