Search code examples
jakarta-eecdi

CDI producer reached once


I've created this producer:

@RequestScoped
public class StripeWebHookProducer {

    private static String HEADER_SIGNATURE = "Stripe-Signature";

    @Inject @Context private HttpServletRequest request;

    @Produces
    public Event getStripeEvent() {
        Event result = null;
        //...
        return result;
    }
}

As you can see it's scoped at @RequestScoped, so as far I've been able to figure out it should be created each time a request is reached on server.

I'm injecting it on my servlet:

@WebServlet(...)
public class StripeWebhook extends HttpServlet {
    @Inject private Event paymentEvent;

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            switch (this.paymentEvent.getEventType())
            {
                case customer_subscription_trialwillend:
                    break;
                case customer_subscription_updated:
                    break;
            }
            // TODO Auto-generated method stub
            doGet(request, response);
        }
    }

Nevertheless, StripeWebHookProducer.getStripeEvent is reached only once. Any ideas?


Solution

  • Seems like you mismatched annotations on class/bean and on producer method. The thing is, producer method has to be placed inside some CDI bean. In your case this bean is StripeWebHookProducer and you have it @RequestScoped annotation. That's perferctly fine, however, it seems accidental so you might want to re-think that and use another one such as @ApplicationScoped or @Dependent

    Now the producer method itself. The outcome of producer is not affected by annotations on the CDI bean where the producer resides. Instead, it is defined by annotation on that method. Here is some code with explanation.

    @ApplicationScoped
    public class MyBeanWithProducer {
      @Produces
      @Dependent
      public ProducedBean produceIt() {
      }
    }
    

    The above sample is a CDI bean MyBeanWithProducer with application scope. It containts a producer method capable of creating another CDI bean, ProducedBean, which will have scope @Dependent. Note that the scope of produced bean differs from the scope of MyBeanWithProducer. If you define no scope on the producer method, it is @Dependent by default.

    So, what you probably want in your app might look like this:

    @ApplicationScoped // ensures there is only one instance of this bean in your app; assuming you have have no other request based logic here
    public class StripeWebHookProducer {
    
        private static String HEADER_SIGNATURE = "Stripe-Signature";
    
        @Inject @Context private HttpServletRequest request;
    
        @Produces
        @RequestScoped // this will make sure this bean is created on every request anew
        public Event getStripeEvent() {
            Event result = null;
            //...
            return result;
        }
    }