Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java CDI: Dynamically selecting an implementation based on qualifier?

Tags:

java

cdi

I'm trying to make an application extensible by using CDI, but it seems like I'm missing a piece of the puzzle.

What I want: Have a global configuration that will define which implementation of an interface to use. The implementations would have annotations like @ImplDescriptor(type="type1").

What I tried:

 @Produces
 public UEInterface createUserExit(@Any Instance<UEInterface> instance, InjectionPoint ip) {
    Annotated annotated = ip.getAnnotated();
    UESelect ueSelect = annotated.getAnnotation(UESelect.class);
    if (ueSelect != null) {
        System.out.println("type = " + ueSelect.type());
    }

    System.out.println("Inject is ambiguous? " + instance.isAmbiguous());
    if (instance.isUnsatisfied()) {
        System.out.println("Inject is unsatified!");
        return null;
    }

    // this would be ok, but causes an exception
    return instance.select(ueSelect).get();

    // or rather this:
     for (Iterator<UEInterface> it = instance.iterator(); it.hasNext();) {
         // problem: calling next() will trigger instantiation which will call this method again :(
         UEInterface candidate = it.next();
         System.out.println(candidate.getClass().getName());
     }
}

This code is close to an example I've seen: The @Produces method will be used to select and create instances and a list of candidates is injected as Instance<E>. If the method simply creates and returns an implementation, it works fine. I just don't know how to examine and select a candidate from the Instance<E>. The only way of looking the the "contents" seems to be an Iterator<E>. But as soon as I call next(), it will try to create the implementation... and unfortunately, calls my @Produces method for that, thereby creating an infinite recursion. What am I missing? How can I inspect the candidates and select one? Of course I want to instantiate only one of them...

Thanks in advance for any help and hints!

like image 825
Finch Avatar asked Jul 31 '26 03:07

Finch


1 Answers

I think the issue is you are trying to select the annotation's class rather than using the annotation as a selector qualifier. Using the class directly searches for an implementation that implements that class. You need to create an AnnotationLiteral using the @ImplDescriptor class to perform a select using it as a qualifier. Create a class extending AnnotationLiteral like so.

public class ImplDescriptorLiteral extends AnnotationLiteral<ImplDescriptor> implements ImplDescriptor {
    private String type;
    public ImplDescriptorLiteral(String type) {
        this.type = type;
    }

    @Override
    public String type() {
         return type;
    }

}

then you can pass an instance of this class to the select method using the type you want.

instance.select(new ImplDescriptorLiteral("type1")).get();

Refer to the Obtaining a contextual instance by programmatic lookup documentation for more information.

like image 168
Brian Blonski Avatar answered Aug 01 '26 15:08

Brian Blonski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!