Search code examples
jakarta-eejbossmodulecdi

Is it possible to inject a custom JBoss module without producer method using CDI?


I have a custom JBoss 7 module which provides services (for example, EmailService for sending e-mails). I want to use these services in applications that are deployed on the same AS.

I specified jars of the service in module.xml (located in modules/jboss/module/main).

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="jboss.module">
  <resources>
    <resource-root path="email-service-api.jar" />
    <resource-root path="email-service-impl.jar" />
  </resources>
</module>

The email-service-api.jar contains only interface of the service. I use this as a dependency for an implementation of the interface (in email-service-impl.jar) and in the applications that use the service.

In email-service-impl.jar there is a file named jboss.module.EmailService (in META-INF/services folder). The file contains fully qualified names of all my implementations (so far I have only one):

jboss.module.impl.DefaultEmailService

I would like to inject the service into an application.

Currently, I use producer method to get instance of the service from an application.

package bean;

public class Bean {

    @Inject
    EmailService emailService;

    @Produces
    public EmailService getEmailService() {
        ServiceLoader<EmailService> emailServices = ServiceLoader.load(EmailService.class);

        for (EmailService emailService : emailServices) {
            if (emailService != null) {
                return emailService;
            }
        }

        return null;
    }
}

When I leave out the producer method I get org.jboss.weld.exceptions.DeploymentException saying WELD-001408 Unsatisfied dependencies for type [EmailService] with qualifiers [@Default] at injection point [[field] @Inject bean.Bean.emailService]"}}.

I have jboss-deployment-structure.xml file in the application:

<jboss-deployment-structure>
  <deployment>
    <dependencies>
      <module name="jboss.module" services="export" />
    </dependencies>
  </deployment>
</jboss-deployment-structure>

And I have tried to add beans.xml file into the "implementation-project" (i.e. email-service-impl.jar), but it had no effect. The exception occured anyway.

Is it possible to inject the service and omit the producer method using CDI?

Thank you,

Denis


Solution

  • Summing up what I wrote in the comments:

    • Producers are probably a way to go here.
      • You are seeking to inject a service which you first need to load. CDI has a static nature and can only inject beans which were available during its boot time. The way around it is to use a producer.
      • To differentiate in between different implementations, you can use qualifiers. E.g. each producer and injection point will have a given qualifier (@DefaultImpl, @ProUser etc).
      • You might be able to put these producers in your API JAR so as not to pollute your code (plus add empty beans.xml).
    • As for other ways apart from producers
      • I can only think of Extension here since they are executed as CDI boots therefore allowing you to register the implementations as beans.
      • This would make the beans available on CDI boot and therefore injectable without producers.
      • However, this approach would prove much more complex.