CDI中带不同限定符的生产者方法注入歧义问题及解决方案咨询
This is all down to CDI's qualifier matching rules: a producer method is considered a candidate if its set of qualifiers includes all the qualifiers specified at the injection point (extra qualifiers on the producer are allowed).
When you inject with just @Inject @Qualifier1 MyBean:
produce1has exactly@Qualifier1—it's an exact match, so it's a valid candidate.produce2has both@Qualifier1and@Qualifier2—since it includes all the qualifiers from the injection point (@Qualifier1), CDI also considers it a valid candidate.
CDI can't pick between them by default, hence the AmbiguousResolutionException.
Since you can't modify the third-party produce1, you can give your custom produce2 a lower priority. This tells CDI to prefer the third-party producer when both are candidates, but still use your producer when the injection point requires both qualifiers.
Update your producer like this:
@ApplicationScoped public class MyProducer { // Third-party producer (unmodifiable) // @Produces // @Qualifier1 // MyBean produce1(InjectionPoint injectionPoint) { ... } @Produces @Qualifier1 @Qualifier2 @Priority(-1) // Lower than the default priority of 0 MyBean produce2(InjectionPoint injectionPoint) { ... } }
How This Works:
- When injecting with only
@Qualifier1: Both producers are candidates, butproduce1has the default priority (0) which is higher thanproduce2's -1. CDI picksproduce1automatically, no ambiguity. - When injecting with both
@Qualifier1and@Qualifier2: Onlyproduce2matches (sinceproduce1doesn't have@Qualifier2), so it gets selected.
If you're using CDI 2.0 or newer, you can create a custom condition that only activates produce2 when the injection point has both qualifiers. This eliminates ambiguity at the source.
First, create a condition class:
public class BothQualifiersPresentCondition implements Condition { @Override public boolean matches(ConditionContext context) { InjectionPoint injectionPoint = context.get(InjectionPoint.class); if (injectionPoint == null) return false; boolean hasQualifier1 = injectionPoint.getQualifiers() .stream() .anyMatch(q -> q.annotationType().equals(Qualifier1.class)); boolean hasQualifier2 = injectionPoint.getQualifiers() .stream() .anyMatch(q -> q.annotationType().equals(Qualifier2.class)); return hasQualifier1 && hasQualifier2; } }
Then apply the condition to your producer:
@ApplicationScoped public class MyProducer { // Third-party producer (unmodifiable) // @Produces // @Qualifier1 // MyBean produce1(InjectionPoint injectionPoint) { ... } @Produces @Qualifier1 @Qualifier2 @Conditional(BothQualifiersPresentCondition.class) MyBean produce2(InjectionPoint injectionPoint) { ... } }
How This Works:
produce2will only be considered a candidate if the injection point has both@Qualifier1and@Qualifier2. When injecting with just@Qualifier1, onlyproduce1is a candidate, so no ambiguity.
内容的提问来源于stack exchange,提问作者Simon Wick

