开发者

Weld CDI: how to make one bean class satisfy any of multiple qualifiers?

From reading the Weld docs I don't think this can be done, but I could really do with it, so thought I'd ask - if there's not a way with CDI, maybe there's a pattern workaround...

I've created a custom qualifier with a member:

@Qualifier
@Target({TYPE, METHOD, FIELD, PARAMETER})
@Retention(RUNTIME)
public @interface JobBinding {
    JobType value();
}

JobType is an enum:

public enum JobType {

    JOB_A,
    JOB_B,
// etc - there are quite a few

Say most jobs need building in a slightly different way, so I have builder classes related to the jobs. These are annotated with a JobBinding annotation given the relevant JobType:

@JobBinding(JobType.JOB_A)
public class JobABuilder implements JobBuilder {
....

When I need to build, I use programmatic lookup:

@Inject @Any
private Instance<JobBuilder> builderSource;
private JobType myJobType;
...
builderSource.select(new JobBindingQualifier(myJobType).get();

JobBindingQualifier is a custom class:

public class JobBindingQualifier extends AnnotationLiteral<JobBinding> implements JobBinding {

    private static final long serialVersionUID = -822150300665931157L;

    private JobType ty开发者_运维问答pe;

    public JobBindingQualifier(JobType type) {
        this.type = type;
    }

    @Override
    public JobType value() {
        return type;
   }
}

So far, great - CDI working brilliantly. However, what if 2 of these jobs, JOB_X and JOB_Y, are built in exactly the same way? I only need one builder class, which I'd like to be instantiated for either of those options - new JobBindingQualifier(JobType.JOB_X) or new JobBindingQualifier(JobType.JOB_Y).

If I annotate JobXAndYBuilder with both @JobBinding(JOB_X) and @JobBinding(JOB_Y), I get a compiler error about the duplicated annotation. To get around this I could change the value of the annotation to an array of JobTypes, and you would annotate the builder like

@JobBinding(JobType.JOB_X, JobType.JOB_Y)

with the constructor called there using an ellipsis to produce the array. However, if I did that, how could I look that up programmatically using either of the jobTypes? Weld docs suggest that you would have to have both; I'd need to provide the exact arguments:

builderSource.select(new JobBindingQualifier(JobType.JOB_X, JobType.JOB_Y).get();

when I want either to be sufficient to lookup the class:

builderSource.select(new JobBindingQualifier(JobType.JOB_X).get();
//or
builderSource.select(new JobBindingQualifier(JobType.JOB_Y).get();

Using the array really just changes the value that you have to match when looking up. I really need a way of annotating a class twice with the same qualifier annotation, and then being able to look it up with any combination of them. Otherwise I'll have to provide a builder class each for X and Y, when one would suffice. Any ideas? Thanks in advance!


As I said in my comment there is no straight way to have an OR relation when you have two or more qualifiers on a bean class.

So the solution to have the same Bean with another qualifier is to use the Producer mechanism. In your example you can create you first class as usual :

@JobBinding(JobType.JOB_X)
public class JobABuilder implements JobBuilder {
    ....
}

and after that create a producer method in either in the first class or in a dedicated producers class like that

public class MoreJobsProducer {
    @Produces
    @JobBinding(JobType.JOB_Y)
    protected JobBuilder prodJobYBuilder(@New @JobBinding(JobType.JOB_X)
                                         JobBuilder theJob) {
        return theJob;
    }    
}

In the paramaters of the producer method you Inject your former bean with its own qualifier and the @Newqualifier which create a new instance of the bean to be sure you avoid some scoping issues (read the Weld doc for more info).

It should do the "Job".

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜