1 2 Previous Next 22 Replies Latest reply on Dec 28, 2009 8:08 AM by johaneltes

    Someone got @Named producer injection to work?

      I have the following producer definitions:



      public class JmsTemplateConfigurationProducer {
              
              @Produces int longReceiveTimeout = 3*3600;
              @Produces int shortReceiveTimeout = 100;
      
              @Produces @Named
              public JmsTemplate getErrorQeueTemplate() {     
                      return new JmsTemplate() {
      
                              @Override
                              @Inject @Named("longReceiveTimeout") 
                              public void setReceiveTimeout(long receiveTimeout) {
                                      super.setReceiveTimeout(receiveTimeout);
                              }       
                      };                      
              }
              
              @Produces @Named
              public JmsTemplate getLogQeueTemplate() {               
                      return new JmsTemplate() {
      
                              @Override
                              @Inject @Named("shortReceiveTimeout") 
                              public void setReceiveTimeout(long receiveTimeout) {
                                      super.setReceiveTimeout(receiveTimeout);
                              }       
                      };                      
              }
      }
      
      
      
      I expect the first JMSTemplate to be assigned the name errorQeueTemplate by Weld. I then have the following injection point:
      
      
      private @Inject @Named JmsTemplate errorQeueTemplate;
      
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
      Caused by: org.jboss.weld.DeploymentException: Injection point has ambiguous dependencies. Injection point: field se.callistaenterprise.cadec2010.cdi.javase.basic.JmsTemplateClient.errorQeueTemplate; Qualifiers: [@javax.inject.Named(value=)]; Possible dependencies: [org.jboss.weld.bean-se-module-ProducerMethod-se.callistaenterprise.cadec2010.cdi.javase.basic.JmsTemplateConfigurationProducer.getErrorQeueTemplate(), org.jboss.weld.bean-se-module-ProducerMethod-se.callistaenterprise.cadec2010.cdi.javase.basic.JmsTemplateConfigurationProducer.getLogQeueTemplate()]
      



      /Johan





        • 1. Re: Someone got @Named producer injection to work?
          meetoblivion

          I believe the name for both of those is jmsTemplate which is why it's ambiguous.  It's based on the returned type, not method name.

          • 2. Re: Someone got @Named producer injection to work?

            The CDI spec requires them to be named by the producer method, unless the signature is a javabean getter. In the latter case the name should be the java bean property name. I would expect them to be named errorQeueTemplate and logQeueTemplate repectively.


            CDI spec:


            3.3.8. Default name for a producer method
            The default name for a producer method is the method name, unless the method follows the JavaBeans property getter naming convention, in which case the default name is the JavaBeans property name.



            /Johan

            • 3. Re: Someone got @Named producer injection to work?
              william.drai

              You'd better use qualifiers :


                      @Produces @Error
                      public JmsTemplate getErrorQeueTemplate(@Named("longReceiveTimeout") int receiveTimeout) {     
                              JmsTemplate tmp = new JmsTemplate();
                              tmp.setReceiveTimeout(receiveTimeout);
                              return tmp;                 
                      }
                      
                      @Produces @Log
                      public JmsTemplate getLogQeueTemplate(@Named("shortReceiveTimeout") int receiveTimeout) {               
                              JmsTemplate tmp = new JmsTemplate();
                              tmp.setReceiveTimeout(receiveTimeout);
                              return tmp;                 
                      }
              }
              



              Then


              private @Inject @Error JmsTemplate errorQueueTemplate;
              



              It's a bit more typesafe this way. However it seems that your code should also work. Have you tried :


              private @Inject @Named("errorQueueTemplate") JmsTemplate errorQeueTemplate;
              



              • 4. Re: Someone got @Named producer injection to work?

                Debugging weld shows that the injection point is named errorQueueTemplate as expected. I suspect the problem is name of the produced bean, which seems to be:


                org.jboss.weld.bean-se-module-ProducerMethod-se.callistaenterprise.cadec2010.cdi.javase.basic.JmsTemplateConfigurationProducer.getErrorQeueTemplate()


                /Johan

                • 5. Re: Someone got @Named producer injection to work?
                  • 6. Re: Someone got @Named producer injection to work?
                    meetoblivion

                    no, sorry, i wasn't paying attention as i was typing.


                    the issue's with the injection point, not the producer.


                    your injection points are both named jmsTemplate.  This is why your ints in the rest of your code need to be something like @Named(shortReceiveTimeout).  Weld's not variable name aware as far as i remember.


                    Try changing your injection points to have values in named to match the variable names to see if they get created.

                    • 7. Re: Someone got @Named producer injection to work?

                      The CDI spec requires the injection point @Named-attributed (when value is missing) to default to the name of the field - not to the name of the type of the field:


                      3.11....If an injected field declares a @Named annotation that does not specify the value member, the name of the field is assumed.


                      /Johan

                      • 8. Re: Someone got @Named producer injection to work?
                        meetoblivion

                        Except that you have to take into account this part, right after the part you mention in the spec.



                        If any other injection point declares a @Named annotation that does not specify the value member, the container automatically
                        detects the problem and treats it as a definition error.
                        • 9. Re: Someone got @Named producer injection to work?

                          I only have one injection point with @Named for that type.

                          • 10. Re: Someone got @Named producer injection to work?
                            meetoblivion

                            so just to debug a bit, does it work correctly if you @Named your inject points properly


                            e.g.


                            private @Inject @Named("errorQueueTemplate") JmsTemplate errorQeueTemplate;


                            • 11. Re: Someone got @Named producer injection to work?

                              It works when I add a value for both injection point and producer @Named annotations. If I leave it out for either producer or field injection point, it fails.

                              • 12. Re: Someone got @Named producer injection to work?

                                I'd like to stress that I think the support for implicit by-convention naming defined by CSI makes a lot of sense. Using strings deviates from the spirit of type safety. Declaring custom annotation (to get custom qualifiers) makes a big footprint in small- to midsized projects - especially when the end-goal is to find a CDI-counterpart of Spring property configuration.

                                • 13. Re: Someone got @Named producer injection to work?
                                  meetoblivion

                                  there's a downside to @Named that you may not have thought of.  everything that's @Named is exposed to the view layer.  this could be a bit dangerous.


                                  another thing to note, you can get creative with your qualifiers.  if you give them enums or strings, you can make them more flexible.  right here you are exposing a more complex use case in the realm of CDI, two instances of an object that mean different things.


                                  This is how I would write your code:




                                  @Produces @Templated(TemplateType.ERROR)
                                  public JmsTemplate getErrorQeueTemplate(@Named("longReceiveTimeout") int receiveTimeout) {     
                                          JmsTemplate tmp = new JmsTemplate();
                                          tmp.setReceiveTimeout(receiveTimeout);
                                          return tmp;                 
                                  }
                                          
                                  @Produces @Templated(TemplateType.LOG)
                                  public JmsTemplate getLogQeueTemplate(@Named("shortReceiveTimeout") int receiveTimeout) {               
                                          JmsTemplate tmp = new JmsTemplate();
                                          tmp.setReceiveTimeout(receiveTimeout);
                                          return tmp;                 
                                  }



                                  in this case, you need 1 additional qualifier (Templated) and an enum that specifies the types of Templates.  The injection points then become




                                  @Inject @Templated(TemplateType.ERROR) JmsTemplate errorTemplate;
                                  @Inject @Templated(TemplateType.LOG) JmsTemplate logTemplate;



                                  You can simplify it further if you'd like, using Strings as the value instead of TemplateTypes, and who knows, maybe Seam3 will have support for producing JmsTemplates, as an even better use case would be:






                                  @Target({METHOD, FIELD, PARAMETER, TYPE})
                                  @Retention(RUNTIME)
                                  @Qualifier
                                  public @interface JmsType {
                                      String name() default "";
                                      int timeout() default 30;
                                  }







                                  @Produces public JmsTemplate produceJMSTemplate(InjectionPoint injectionPoint)
                                     {
                                        if (injectionPoint.getAnnotated().isAnnotationPresent(JmsType.class)) {
                                            JmsType t = injectionPoint.getAnnotated().getAnnotation(JmsType.class);
                                            JmsTemplate tmp = new JmsTemplate();
                                            tmp.setReceiveTimeout(t.timeout());
                                            return tmp;
                                        }
                                        else {
                                           return new JmsTemplate();
                                        }
                                     }



                                  Mind you, i've only played with it a little so no claims this will actually work 100% just from this code.

                                  • 14. Re: Someone got @Named producer injection to work?

                                    @Produces public JmsTemplate produceJMSTemplate(InjectionPoint injectionPoint)...


                                    ...This would be immensely cool. Is this a feature of CDI today, or a vision for a forthcoming version?


                                    It would completely reduce the need for been property configurations!


                                    /Johan

                                    1 2 Previous Next