0

I have a class

@RequestScoped
public class AFactory {

  private final HttpServletRequest request;

  protected AFactory () {
    this.request = null;
  }

  @Inject
  public AFactory (HttpServletRequest request) {
    this.request = request;
  }

  @Produces
  public A getA() {
    int random = ...;
    A a = new A(request);
    a.setRandom(random);
    return a;
  }

}

I understand since I am doing new A(), I return the real instance.

Is this the expected way to use producers?

Is there a way to return the proxied instance?

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
Mayday
  • 4,680
  • 5
  • 24
  • 58
  • Afaik, the method that is annotated with `@Produces` is effectively the proxy. That method is 'injected'. So you get a new instance ech time it is called because you create a new instance IN the method each time. If you 'lazy' instantiate it, you'll get the same A back each time, so there is no need to have proxies. But I might be wrong... – Kukeltje May 07 '19 at 14:55
  • And regarding the 'right way (or wrong way)' is tota;;y dependend on your use case... Do you need the state of A to be consistent across calls (your 'random') or not. If not, the way you use it is fine, if it needs to be the same, do it lazy. – Kukeltje May 07 '19 at 15:00
  • @Kukeltje I need it to be `@RequestScoped`, therefore, the same instance, with exact same random number between all beans using it during that request – Mayday May 07 '19 at 15:06
  • Then do it in the constructor or 'lazy' in the getter... plain simple all basic java. – Kukeltje May 07 '19 at 15:46
  • Allthough my answer 'solved' your problem, my assumption on why it behaved like you see was wrong. It solved it by working around CDI behaviour and solving it in the traditional java way. Please unaccept my answer and accept the other one so I can remove my answer. – Kukeltje May 08 '19 at 08:33
  • @Kukeltje Thanks for your sincerity. However, I think it could help other people as a workaround. Maybe just editing your answer and marking it as workaround might be useful too :) :) – Mayday May 08 '19 at 08:57
  • Agreed... ! will do – Kukeltje May 08 '19 at 09:12

1 Answers1

4

CDI installs proxies for beans of all scopes except for the @Dependent pseudo scope. A @Produces annotated method (short producer) is called by CDI whenever it needs to get a (new) instance of a bean. This instance is then put into some pool for the corresponding scope.

The proxy will always return the bean-instance from the pool. Try adding some debug message to the producer method to see how often it will be called. A producer for an @ApplicationScoped bean should be called only once, and a @RequestScoped producer should be called once per request.

In the examples above no scope is given to the producer method (the scope of the factory class is not used for the producer method), so the default scope (@Dependent) will be used. And this means (as no proxy is used for this scope), a new instance will be injected every time @Inject A is found by CDI. See also this Question and Answer and the referenced documentation for more details.

So to your concrete questions:

  • The observed behavior is expected
  • Proxies will only be used if scope is not @Dependet which is the default.
Martin Höller
  • 2,714
  • 26
  • 44
  • 1
    This is indeed correct. Just one tiny addition - `@javax.inject.Singleton` (*not* the EJB one!) is also a proxy-less scope and will always use the real instance. – Siliarus May 13 '19 at 10:50