简体   繁体   English

Java CDI:根据限定符动态选择实现?

[英]Java CDI: Dynamically selecting an implementation based on qualifier?

I'm trying to make an application extensible by using CDI, but it seems like I'm missing a piece of the puzzle. 我试图通过使用CDI使应用程序可扩展,但似乎我错过了一块拼图。

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"). 实现将具有类似@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>. 这段代码接近我见过的一个例子:@Produces方法将用于选择和创建实例,候选列表将作为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>. 我只是不知道如何检查并从Instance <E>中选择一个候选者。 The only way of looking the the "contents" seems to be an Iterator<E>. 查看“内容”的唯一方法似乎是迭代器<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. 但是一旦我调用next(),它就会尝试创建实现......不幸的是,为此调用我的@Produces方法,从而创建无限递归。 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! 在此先感谢任何帮助和提示!

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. 您需要使用@ImplDescriptor类创建AnnotationLiteral,以使用它作为限定符来执行选择。 Create a class extending AnnotationLiteral like so. 像这样创建一个扩展AnnotationLiteral的类。

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. 然后,您可以使用所需的类型将此类的实例传递给select方法。

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

Refer to the Obtaining a contextual instance by programmatic lookup documentation for more information. 有关详细信息,请参阅通过编程查找文档获取上下文实例

Finch, what you have here should work. 芬奇,你在这里应该有所作为。 it assumes though that you have an instance of UEInterface that is annotated @UESelect , eg 它假设你有一个UEInterface的实例注释了@UESelect ,例如

@UESelect("one")
public class UEOne implements UEInterface {
..
}

Is this how you're expecting it to work? 这是你期望它如何工作?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM