1 Reply Latest reply on Jun 26, 2011 9:30 AM by Joshua Davis

    Qualifiers vs concrete implementations at injection points

    Wujek Srujek Newbie

      Hi. Suppose I have an interface Payment, and two implementations / qualifiers combinations: PayPalPayment qualified with @PayPal, and CashPayment qualified with @Cash.
      Then, I have another bean that has an injection point that accepts a Payment. Now I have two choices (for CDI to be able to disambiguate the injection target):
      1. @Inject @PayPal / @Cash Payment payment - in this case, I use the qualifier
      2. @Inject PayPalPayment / CashPayment payment - here, I don't use qualifiers and use the concrete type directly


      Now, I haven't been able to understand yet, why is @Inject with a qualifier that is bound to a concrete implementation better than simply @Inject with the concrete implementation itself.
      Suppose I use option 1 (qualifiers, and use @PayPal). If, after some time, I want to change it to @Cash, I have to go to the code, change the qualifier and recompile again. If I use option 2 (disambiguation by types), I have to do just the same thing - change the code and recompile. But - I have fewer classes to manage, and smaller learning curve for juniors (ok, these arguments are a little stretched ;d).


      The only point I see is that if you inject the concrete impl without qualifier, you might accidently use methods of the impl and pass it around to other classes as result of some method calls (but if someone else need a payment, they should inject their own anyways, I guess; passing objects like this seems to violate the Law of Demeter) and these other classes might use impl-specific methods, not just the interface methods. Then, if you do decide to change the implementation, you can get compilation errors for such methods, because they existed for PayPal, but it is no longer true for Cash. Having said that, testing and mocking would show this problem, and since you have to recompile anyways, I am not sure if it's a big deal.


      Please anybody correct me if I am wrong. Other than the reason stated above, I am clueless about why one would need qualifiers. But, as smarter than me invented them, I assume I am missing something.


      Regards,
      wujek

        • 1. Re: Qualifiers vs concrete implementations at injection points
          Joshua Davis Expert

          Wujek Srujek wrote on Jun 25, 2011 05:34:


          Now, I haven't been able to understand yet, why is @Inject with a qualifier that is bound to a concrete implementation better than simply @Inject with the concrete implementation itself.


          It is 'better' if you value decoupling and implementation hiding.   The client code only depends on the interface and the qualifier annotation.   This is a 'simpler' design from the dependency perspective, but ... as you said it might be confusing to junior engineers.



          The only point I see is that if you inject the concrete impl without qualifier, you might accidently use methods of the impl.


          And that will strongly couple the client code to the implementation, which may end up being a very bad thing down the line.


          If you really want to be modular, put the interface, all the transfer objects, and the qualifier in an 'api' module.   Then your modules have a logical and clean dependency graph.



          I guess; passing objects like this seems to violate the Law of Demeter) and these other classes might use impl-specific methods, not just the interface methods. Then, if you do decide to change the implementation, you can get compilation errors for such methods, because they existed for PayPal, but it is no longer true for Cash. Having said that, testing and mocking would show this problem, and since you have to recompile anyways, I am not sure if it's a big deal.


          It depends on the value decoupling and modularity provides going forward.  For example, if you think that you'll be adding new payment methods, or perhaps deciding which payment method to inject at runtime, then using an interface will provide some benefits.


          As far as re-compiling things go, I'm not sure why that is important in this age of fast compilers and automatic build tools like Maven.   As I had mentioned before, if you give the API it's own module then you get some de-coupling, which should allow a more parallel development effort.


          Like I said, it all depends on whether the de-coupled, modular design is valuable to your situation.   It isn't always the case.