14 Replies Latest reply on May 29, 2006 12:20 PM by Gavin King

    Injection via abstract getters

    Andris Birkmanis Newbie

      Another question (or mayb suggestion on advancement of data-flow synchronization):
      currently it looks that Seam performs all injections for a component before entering any method of the component (provided interception criteria are met), even if the component is not going to use these values during the invocation.

      Why not support yet another kind of injection - via abstract getters of the component, thus giving the finest possible data-flow synchronization? In this way, the values are injected as late as possible (or never, if not needed). This is not only an optimization, but can also simplify development of components (less explicit synchronization).

      And if we go that far, why not allow these getters to accept parameters, and in general be just any methods?

      I realize that this would require bytecode enhancement, but Seam already does it for POJOs.

        • 1. Re: Injection via abstract getters
          Gavin King Master

          A class with abstract methods is not a valid EJB bean and would not be able to be deployed by the container.

          If you need laziness, just call Contexts.lookup()

          • 2. Re: Injection via abstract getters
            Andris Birkmanis Newbie

            Contexts.lookup() is not type safe.

            Abstract getters need not be abstract from Java point of view, just conceptually.
            For example, their body can do nothing but throw UnsupportedOperationException.

            • 3. Re: Injection via abstract getters
              Gavin King Master

              Right, but nevertheless, this is a problem if the EJB container controls instantiation of the component.

              • 4. Re: Injection via abstract getters
                Andris Birkmanis Newbie

                What exactly is a problem? A method that throws an exception? But interceptors are not obliged to call it, right?

                • 5. Re: Injection via abstract getters
                  Jim Hazen Expert

                  The problem is that EJBs can't be abstract. That's an EJB requirement, not a Seam choice. Since Seam deals primarily in EJBs, Gavin can't help you much here.

                  Seam does support non EJB POJOs, however I wouldn't think the semantics of the framework should change to support abstract JavaBean components. The semantics should be uniform and unfortunately that forces you to conform to the lowest common denominator. Anyway, I think the lack of abstract EJB support is the problem you're looking for.

                  -Jim

                  • 6. Re: Injection via abstract getters
                    Gavin King Master

                    Note that I am also in priciple against the idea of writing components in terms of abstract classes, since it is significantly more difficult to unit test them (not impossible, but certainly more difficult).

                    • 7. Re: Injection via abstract getters
                      Andris Birkmanis Newbie

                      I might have not stressed that enough in the previous posts, but I meant the methods to be conceptually abstract, not formally, e.g.:
                      @Name("a")
                      public class ComponentA
                      {
                      @In("b")
                      protected IComponentB getB()
                      {
                      throw new UnsupportedOperationException();
                      }

                      public void doStuff()
                      {
                      getB().doSomeOtherStuff();
                      // more stuff
                      }
                      }

                      Note that both class ComponentA and method getB should be abstract, but are not.

                      Is it against the EJB spec to have such SFSB?
                      Also, I do not see how this class is difficult to test.

                      • 8. Re: Injection via abstract getters
                        Gavin King Master

                        It is difficult to test because

                        new ComponentA().doStuff() throws an UOE. I have to subclass the class before I can call its methods.

                        • 9. Re: Injection via abstract getters
                          Gavin King Master

                          By the way, it is utterly irrelevant whether it is "conceptually" or actually abstract. In either case my arguments apply.

                          • 10. Re: Injection via abstract getters
                            Andris Birkmanis Newbie

                             

                            "gavin.king@jboss.com" wrote:
                            It is difficult to test because

                            new ComponentA().doStuff() throws an UOE. I have to subclass the class before I can call its methods.


                            OTOH, componentAFactory.newInstance().doStuff() works fine.
                            Also note that in case of eager injections (the current mechanizm) new ComponentA().doStuff() throws an NPE, which is hardly better.

                            • 11. Re: Injection via abstract getters
                              Andris Birkmanis Newbie

                               

                              "gavin.king@jboss.com" wrote:
                              By the way, it is utterly irrelevant whether it is "conceptually" or actually abstract. In either case my arguments apply.

                              Testing is marginally more complex, that's true. But I believe this is outweighted by the improved runtime guarantees.

                              And the difference between actually and conceptually abstract classes is that the former are not legal EJBs, while the latter are.

                              • 12. Re: Injection via abstract getters
                                Jim Hazen Expert

                                 

                                "abirkmanis" wrote:
                                Also note that in case of eager injections (the current mechanizm) new ComponentA().doStuff() throws an NPE, which is hardly better.

                                Had getB() actually been abstract rather than "conceptually" abstract, the compiler wouldn't have even let you create an instance of new ComponentA(). Maybe Seam could do some additional runtime error checking, but something that would have broken in the real world, still breaking in the conceptual world is hardly a shocker.

                                And even if you were to subclass ComponentA, things still wouldn't work because @In isn't inherited.

                                Seam components are first class concrete constructs. I don't see a problem with a component's implementation extending an abstract class, but I don't see the value of an abstract component. I do see the problems associated with trying to fake them though.

                                "abirkmanis" wrote:
                                OTOH, componentAFactory.newInstance().doStuff() works fine.

                                Why not simply do something like this via @Factory or @Unwrap? I'm trying to help, but don't see where this abstractness gets you anything but pain, now, and then later in testing.

                                • 13. Re: Injection via abstract getters
                                  Andris Birkmanis Newbie

                                   

                                  "CptnKirk" wrote:
                                  "abirkmanis" wrote:
                                  Also note that in case of eager injections (the current mechanizm) new ComponentA().doStuff() throws an NPE, which is hardly better.

                                  Had getB() actually been abstract rather than "conceptually" abstract, the compiler wouldn't have even let you create an instance of new ComponentA().

                                  I meant if I were using the current injections (via setters, not getters), and didn't inject anything for B, but just called doStuff(), I would get an NPE.

                                  Just rewrite the code I suggested to return null instead of throwing UOE, and the failure will be the same for both patterns - NPE in face of missing injection.

                                  Note that I didn't talk about subclassing my component class, Seam could just intercept the call to getB, lookup the value of B and return the value - JIT injection, not sooner when needed.
                                  This JIT nature of injection via getters is their added value compared to injection via setters or fields.
                                  The same effect could be achieved by using Contexts.lookupInStatefulContexts and a type cast inside getB, but then why using annotations and interceptors at all? :-)


                                  • 14. Re: Injection via abstract getters
                                    Gavin King Master

                                    Forget about the abstract getters/setters for now, that is a horrible implementation of laziness anyway.

                                    A good implementation would be to have proxies for the components which actually create the underlying component instance when first invoked. Seam could do that. But it seems to me that the EJB container could do it just as easily, since it already has a proxy.