0

I'm using WELD SE on a standalone java project which seemed to work fine till I started using producers.

The producer method works - the container uses it, but never injects the inner pdependencies of the produced bean. When I remove the producer, it works normally. I can't find the cause even after a long search on the spec and on Google.

Example of a Producer:

@ApplicationScoped
public class LaminaValidadorProducer {

    private static final String XSD_PATH = getConfig("processador.xsd.path");
    private static final Map<VersaoLamina,String> XSD_PER_VERSION = new HashMap<>();
    static {
        XSD_PER_VERSION.put(VersaoLamina.V1, getConfig("processador.lamina.xsd.file"));
        XSD_PER_VERSION.put(VersaoLamina.V2, getConfig("processador.laminav2.xsd.file"));        
    }

    @Produces
    public LaminaValidador buildValidador() {
        return new LaminaValidador(XSD_PATH, XSD_PER_VERSION);
    }
}

LaminaValidador is injected normally, but its INNER attributes (marked with @Inject) are not being injected. THe project has a beans.xml with bean-discovery-mode="all".

Any clues on what's happening?

Valerio Lopes
  • 79
  • 1
  • 9

1 Answers1

1

This is not only a matter of SE and it is in fact a desired/expected behaviour of CDI.

The reason behind this is that normally, if you do not have producers, CDI creates the bean classes for you (by calling no-args constructor, or one with injections) and subsequently resolves the injection points within the bean (and does some other things, see spec). E.g. you leave the lifecycle management to CDI container.

On the other hand, using a producer is usually a way to create a bean out of a class where:

  • you cannot control lifecycle youself, e.g. EntityManager
  • you intergrate with other frameworks and they have complex initialization
  • you need to do some checks for external config before calling certain constructor
  • or you maybe want a bean for a primitive type (int)
  • and many many more use cases

Now this means you are responsible for the creation of the bean. And that includes any fields within. Container just takes the producer as a way to create a full-blown bean and assumes you took care or what the initialization required.

Now, from your question I judge you need the injection point resolution inside. There is no easy way, if any, to "enforce" the resolution manually due to static nature of CDI (and other, more complex reasons). Hence I would propose to use a different approach and leverage constructor injection or maybe initializer methods? If you provide more information, I might be able to help.

Siliarus
  • 6,393
  • 1
  • 14
  • 30
  • Shame on me - basic stuff I wasn't aware of. Thank you. I never had to make a Producer of a bean with inner dependencies marked with @Inject, so it always worked - in my head, once you passed the arguments to the constructor, CDI would continue to inject the attributes marked explicitly with Inject. This would be hard to implement, so I think the behaviour of the framework is correct. – Valerio Lopes Oct 25 '16 at 17:51
  • I could solve the problem by wrapping this map (see my post) in another class (with no extra dependencies). So, I made a producer of this class (which works fine) and then @inject it in the LaminaValidador via constructor. Now works like a charm. Thanks again. – Valerio Lopes Oct 25 '16 at 17:53
  • Glad I could help! BTW wrapping with another class sure works but you could also create a producer method, which will produce you map (and in the method's body you would initialize it as you wish). Such producer method could reside in the the same class you have now. Then you could inject the map anywhere, including the constructor of your `LaminaValidador` class (e.g. [using constructor injection](http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#declaring_bean_constructor)). – Siliarus Oct 31 '16 at 09:18