javajakarta-eecdipayara

CDI: Injecting single instance works, but injecting Instance<> does not. Why?


I'm trying to implement somewhat of a "plugin feature" with the help of CDI injection. But i'm having some trouble and thought i might get some outside perspective from my fellow "Stackers" :-)

I got so far that something like this works:

@Inject 
@ScoringModule("AGE")
private AgeModule ageModule;

@Inject 
@ScoringModule("CUSTOMER_TYPE")
private CustomerTypeModule customerTypeModule;

When i "run" this then both fields get injected with the appropriate instances. But when i try to inject them a bit more "dynamically" like this:

@Inject @Any
private Instance<CustomerScoringModule> scoringModuleInstance;

CustomerScoringModule module = scoringModuleInstance.select(new ScoringModuleLiteral("AGE")).get();

Then i will get an exception like this:

org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001334: Unsatisfied dependencies for type CustomerScoringModule with qualifiers @Any @ScoringModule

This seems strange to me because CDI clearly "knows" about the instances i'm interested in, because the direct injection into the typed fields is working. So I'm assuming it must have something to do with the qualifiers? Somehow CDI "sees" those two instances but decides that none of them are appropiate for my injection request? could that be it?

Is there anything "obvious" that comes to mind that i might be doing wrong here? I'm trying to use CDI for the first time and it's possible (or even probable) that i'm doing something stupid somewhere :-)

Any help or hint is appreciated and many thanks in advance!

Below I'll attach the "surrounding" classes for the qualifier and the annotation literal and so forth for reference.

The CustomerScoringInterface that both modules implement:

package de.otto.cccs.customerscoring.modules;

import de.otto.cccs.customerscoring.modules.vo.ScoringModuleResponseVO;
import de.otto.cccs.customerscoring.valueobjects.webservice.ScoringRequestVO;

public interface CustomerScoringModule {
    public ScoringModuleResponseVO process(ScoringRequestVO inputVO);
}

One of the two module implementations (they are just dummy implementations right now and the only difference is the log.info() output in the process() method, thats why im only including one of them here):

package de.otto.cccs.customerscoring.modules;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;

import de.otto.cccs.customerscoring.modules.qualifiers.ScoringModule;
import de.otto.cccs.customerscoring.modules.vo.ScoringModuleResponseVO;
import de.otto.cccs.customerscoring.valueobjects.webservice.ScoringRequestVO;
import lombok.extern.log4j.Log4j2;

@Log4j2
@Stateless
@LocalBean
@ScoringModule("AGE")
public class AgeModule implements CustomerScoringModule {

    public AgeModule() {
        super();
    }

    @Override
    public ScoringModuleResponseVO process(ScoringRequestVO inputVO) {
        log.info("processed AGE_MODULE");

        return new ScoringModuleResponseVO();
    }

}

The @ScoringModule qualifier:

package de.otto.cccs.customerscoring.modules.qualifiers;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface ScoringModule {
    String value();
}

And the AnnotationLiteral:

package de.otto.cccs.customerscoring.modules.qualifiers;

import javax.enterprise.util.AnnotationLiteral;

public class ScoringModuleLiteral extends AnnotationLiteral<ScoringModule> implements ScoringModule {

    private static final long serialVersionUID = 1L;
    private String value;

    public ScoringModuleLiteral(String value) {
        this.value = value;
    }

    @Override
    public String value() {
        return this.value;
    }
}

And finally my empty beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

Solution

  • I ended up changing the modules from EJB's to plain Java classes and all my troubles went away.

    I didn't really need the modules to be EJB's i just wrongly assumed in the beginnig that they had to be to be injected via CDI, which is not the case anymore (it was true with older J2EE releases)

    Thanks for the Feedback!