10 Replies Latest reply on Feb 18, 2010 4:42 AM by John Ament

    Feature Request? programatic constructor parameter

    Pieter Martin Novice

      Hi,


      I have a need to pass a constructor parameter to a bean without there being a producer method to provide the value for the parameter.


      My usecase is as follows.





           @Inject
           private JmsExecutorService executorService;
              private int numberOfMessages;
      
      ...
              public void startSendingMessages() {
      
                  //Query / do something or other
                  this.numberOfMessages = 100;
      
               for (int i = 0; i < numberOfMessages; i++) {
                this.executorService.submit(new Message());
               }
              }
      
      ...
      
           @Produces
           public int getNumberOfMessages() {
                return this.numberOfMessages;
           }
      



      However I would like to replace having a producer method with



      this.executorService = executorServiceInstance.get(numberOfMessages);



      I realize there is no real advantage except for this except for that I will not have to explain to the clients of JmsExecutorService what a producer method is and that it is required for JmsExecutorService to work. (They are somewhat hesitant and reluctant to start using weld). Further they easily will understand that numberOfMessages is being passed in as a as a constructor parameter.


      Though I have not used google guice I understand they have such a feature in their extensions.


      Thanks
      Pieter








       

        • 1. Re: Feature Request? programatic constructor parameter
          John Ament Master

          I think you might need to describe a bit clearer what you're aiming for.  I know that a number of enhancements are on the way, however, CDI has a fairly extensive portable extension API that may help you do what you're looking to do.

          • 2. Re: Feature Request? programatic constructor parameter
            Arbi Sookazian Master

            I think he is asking for a technique/solution/design that will allow the client (JMS) to avoid the use of a producer method, thereby not being involved with the CDI API, directly or indirectly?  Something like this...


            Why don't you add a layer of indirection, like a delegate class, that will do the dirty work to directly call the producer method, that way the JMS client won't even know (don't tell the police!)

            • 3. Re: Feature Request? programatic constructor parameter
              Pieter Martin Novice

              Hi,


              I added a Factory class that does the dirty work so to speak.


              @ApplicationScoped
              public class JmsExecutorServiceFactory {
              
                   @Inject
                   private Instance<JmsExecutorService> jmsExecutorServiceInstance;
                   private int numberOfMessages;
                   
                   public JmsExecutorService getJmsExecutorService(int numberOfMessages) {
                        this.numberOfMessages = numberOfMessages;
                        return jmsExecutorServiceInstance.get();
                   }
                   
                   @Produces
                   public int getNumberOfMessages() {
                        return this.numberOfMessages;
                   }
                   
              }



              So now the client can call




                   @Inject
                   private JmsExecutorServiceFactory executorServiceFactory;
              
                      ...
              
                      public void doStuff() {
                          int numberOfMessages = 10;
                           JmsExecutorService jmsExecutorService = executorServiceFactory.getJmsExecutorService(numberOfMessages);
                        
                       for (int i = 0; i < numberOfMessages; i++) {
                        jmsExecutorService.submit(new ExecutorImpl());
                       }
                      }
              



              I asked some colleques, the feature in google guice to add constructor parameters via the Instance<Object> dribble.get(parameter) is called Assisted Inject


              Thanks
              Pieter

              • 4. Re: Feature Request? programatic constructor parameter
                John Ament Master

                You can actually do a lot more with Producer methods.  The main problem I see is that your code isn't thread safe, so it's likely to blow up.  Have you considered something like the following? (Note, I have no idea how JmsExecutorService works)



                     @Inject @NumberOfMessages(10)
                     private JmsExecutorService jmsExecutorService;
                
                        ...
                
                        public void doStuff() {
                         for (int i = 0; i < numberOfMessages; i++) {
                          jmsExecutorService.submit(new ExecutorImpl());
                         }
                        }








                @ApplicationScoped
                public class JmsExecutorServiceFactory {
                
                     @Inject
                     private Instance<JmsExecutorService> jmsExecutorServiceInstance;
                     
                     @Produces @NumberOfMessages
                     public JmsExecutorService produceJmsExecutorService(InjectionPoint ip) {
                          int numberOfMessages = ip.getAnnotated().getAnnotation(NumberOfMessages.class).numberOfMessages();
                          ....
                          return jmsExecutorServiceInstance.get();
                     }
                     
                }



                • 5. Re: Feature Request? programatic constructor parameter
                  Pieter Martin Novice

                  No I had not considered the way you suggest. Looks more eloquent, thanks.


                  For now the JmsExecutorService is only being called from the main thread in a SE app so thread safety is ok. That said I'll most likely have to make it able to be called from separate threads.


                  The JmsExecutorService.submit sends of a jms message. A result is return via another jms queue. The numberOfMessages is used to create a CountDownLatch which is used to know when all the results have arrived. I then fire a complete event to inform the main thread that all results have been received.


                  The observer event model will not work anymore in multiple threads as I do not know how to distinguish the events between threads. When conversations come to Weld-SE this should be easier.


                  Thanks for the advice.


                  Pieter


                  • 6. Re: Feature Request? programatic constructor parameter
                    Pieter Martin Novice

                    Hi,


                    Problem with the @NumberOfMessages(10) approach is that the numberOfMessages is only known runtime.

                    • 7. Re: Feature Request? programatic constructor parameter
                      Gavin King Master

                      We will not be adding assisted inject to CDI or Weld, because it is non-typesafe. If Java had typesafe method parameter literals, it could be made typesafe, but that's incredibly unlikely to ever happen.

                      • 8. Re: Feature Request? programatic constructor parameter
                        Gavin King Master

                        Gavin King wrote on Feb 17, 2010 16:31:


                        We will not be adding assisted inject to CDI or Weld, because it is non-typesafe. If Java had typesafe method parameter literals, it could be made typesafe, but that's incredibly unlikely to ever happen.


                        Oh and because the container-generated-factory-implementation thing is hard to test.

                        • 10. Re: Feature Request? programatic constructor parameter
                          John Ament Master

                          There are other ways to think of it though.  For example, I assume that the value of 10 is set in a bean somewhere? Why not have the producer come off of that bean?