Announcement Announcement Module
Collapse
No announcement yet.
using factory method pattern with a roo entity Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • using factory method pattern with a roo entity

    Hi,

    I just got surprised by Roo a little bit, I hope somebody can explain.

    I have a class Customer which is a RooEntity, for which I want to control the way objects are created, so I create a static factory-method:

    Code:
    public static Customer createCustomer(String someArgument){};
    To complete the use of factory-method, I made one no-argument constructor which i have marked as private.

    I previously had some code that did something like this (outside the Customer class)
    Code:
    Customer customer = new Customer();
    This should cause a compiler error, considering that the constructor is not visible.
    In STS, this line gets a compiler error. However, when I run mvn clean compile, the application actually compiles, which it should not.

    Inspecting the Customer.class file it seems to me that Roo is adding constructors, therefore allowing this object to be new'ed. STS probably somehow doesn't see those constructors.

    So, how do I ensure that I can use the factory method pattern?

  • #2
    Interesting, looking at the Roo generated aspects you will notice that it does actually not introduce a constructor anywhere, that is why STS does the right thing showing the error marker. So the constructor is being introduced by another weaver or a proxy. In this case I would guess that that is Hibernate which needs a default constructor for persisting the entity (it does it by calling Constructor.newInstance()). I'll have a talk with Ben about this after the break.

    Comment


    • #3
      Yep, in the hibernate docs they say a class should provide a no-argument constructor.

      So I suppose the question is that if Roo doesn't create one, how does it get added? I am not aware of Hibernate doing any of this stuff at compile time...

      Comment


      • #4
        Here's how it's supposed to work:

        Hibernate will change the accessibility of a private constructor so it can invoke it.

        Roo will only create a no-arg constructor if the user fails to define a no-arg constructor AND the default constructor would not apply. In other words, if a user creates their own no-arg constructor Roo will not do anything. Roo will also not do anything if the user doesn't declare any constructors at all, as then the default constructor will apply and thus Roo would be making a redundant no-arg constructor.

        The Hibernate and ITD creation semantics above are actually happening correctly.

        However, I have reproduced your issue. It's really quite interesting. If you add a private no-arg constructor to your .java file, Roo will (quite correctly, as noted above) not create any constructor in the ITD. However, by the time ajc runs it will convert the previously-private no-arg constructor into a public no-arg constructor. The reason for this is the _Roo_Entity.aj file contains a method such as the following:

        Code:
            public static final EntityManager Hello.entityManager() {
                EntityManager em = new Hello().entityManager;
                if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
                return em;
            }
        It appears to me the presence of "new Hello()" causes the visibility change. You can verify this by converting the method into the following form (without re-running Roo, of course, as it will overwrite your changes) and attempting a re-compile:

        Code:
            public static final EntityManager Hello.entityManager() {
                EntityManager em = null; // new Hello().entityManager;
                if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
                return em;
            }
        You might be able to solve your immediate problem by writing an enforcement aspect. In the meantime I'll ask Andy to take a look at this, as it's an ajc behavior as far as I can tell.

        Cheers
        Ben

        Comment


        • #5
          Hi ben,

          Thanks for taking the time for this detailed response. Indeed I could use an enforcement aspect for now. Can I expect you to reply in this thread again once you have found a conclusion on this?

          Regards,
          Hans

          Comment


          • #6
            I've received an update from Andy on this topic and he has confirmed ajc changes the visibility.

            So far I've identified three workarounds I could implement via ITDs, but each have downsides of course. Andy also advises he hopes to address this in the near future within AspectJ itself.

            As such I'd recommend an enforcement aspect for now. Andy and I will continue to review options and raise a ticket against the appropriate project (Roo or AspectJ) once we figure out the desired model.

            Comment

            Working...
            X