0

I have an custom qualifier annotation

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

And some beans

@Component
@Scope("prototype")
@MyQualifier(MyQualifierEnum.BLACK)
public class BlackBean {

@Component
@Scope("prototype")
@MyQualifier(MyQualifierEnum.WHITE)
public class WhiteBean {

I try @Lookup but it rely on bean name or class and I can't pass annotation and it attributes to lookup-method

Then I try

context.getgetBeansWithAnnotation(MyQualifier.class)

but it leads to all @MyQualifier beans instantiated that worse for me.

I can't introduce @MyQualifierBlack, @MyQualiferWhite etc separate annotations, I exactly need enum so how I can inject that prototype beans depends on MyQualifierEnum value, for example MyQualifierEnum.BLACK, at runtime without unnecessary initialization of other @MyQualifier annotated beans?

dimedrol90
  • 276
  • 1
  • 4
  • 12
  • So you want to look up the bean via context or some other programatical means instead of @Inject/@Autowiring them into your classes? Maybe look at https://stackoverflow.com/questions/34798459/get-bean-from-applicationcontext-by-qualifier – sfiss Jun 14 '19 at 15:09
  • @sfiss no matter. I can use context and annotation-way both. I research your reference early and can't find solution for my queistion – dimedrol90 Jun 17 '19 at 05:06
  • Is your code working with a different scope? Could you post the code at the injection site? – sfiss Jun 17 '19 at 10:04

1 Answers1

0

The following setup uses only JSR-330 annotations. I did not test it yet for spring, but it works using e.g. hk2 as the implementation:

@MyQualifier(MyQualifierEnum.BLACK)
// Framework-specific annotations, e.g. @Component/@Service and @Scope
public class BlackService implements QualifiableService { }

@MyQualifier(MyQualifierEnum.WHITE)
// Framework-specific annotations, e.g. @Component/@Service and @Scope
public class WhiteService implements QualifiableService { }

@Qualifier
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyQualifier {

    public static enum MyQualifierEnum {
        WHITE, BLACK;
    }

    MyQualifier.MyQualifierEnum value();
}

// Framework-specific annotations
public interface QualifiableService { }

// Framework-specific annotations, e.g. @Component/@Service and @Scope
public class TestComponent {

    @MyQualifier(MyQualifierEnum.BLACK)
    @Inject
    private QualifiableService black;

    @MyQualifier(MyQualifierEnum.WHITE)
    @Inject
    private QualifiableService white;

    @MyQualifier(MyQualifierEnum.WHITE)
    @Inject
    private Provider<QualifiableService> whiteProvider;

    @MyQualifier(MyQualifierEnum.BLACK)
    @Inject
    private Provider<QualifiableService> blackProvider;

    void test() {
        final QualifiableService white = whiteProvider.get();
        final QualifiableService black = blackProvider.get();
    }
}

Make sure you register both implementations (e.g. package scanning in your case) and inject the correct one via qualifier. The equals implementation of annotations should suffice to ensure the correct component is injected.

In the case you use a narrower scope (e.g. prototype scope), using a (qualified) Provider seems the easiest solution. Alternatively, you could try to inject a proxy (e.g. using springs proxy mechanism).

sfiss
  • 2,119
  • 13
  • 19