Problem
Using CDI I want to produce @ApplicationScoped
beans.
Additionally I want to provide a configuration annotation to the injection points, e.g.:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Configuration {
String value();
}
I do not want to write a separate producer for each different possibility of value
.
Approach
The usual way would be to make a producer and handle the injection point annotations:
@Produces
public Object create(InjectionPoint injectionPoint) {
Configuration annotation = injectionPoint.getAnnotated().getAnnotation(Configuration .class);
...
}
By consequence the bean cannot be application scoped anymore, because each injection point could be possibly different (parameter injectionpoint for producers does not work for @AplicationScoped
annotated producers).
So this solution does not work.
Question
I would need a possibility that the injection points with the same value get the same bean instance.
Is there an inbuilt CDI way? Or do I need to somehow "remember" the beans myself in a list, e.g. in the class containing the producer?
What I need is basically an ApplicationScoped
instance for each different value
.
What you try to achieve is not an out fo the box feature in CDI, but thanks to its SPI and a portable extension you can achieve what you need.
This extension will analyse all injection poins with a given type, get the
@Configuration
annotations on each of them and will create a bean in applicationScoped for each different value of the membervalue()
in the annotation.As you'll register multiple beans with the same type you'll have first to transform your annotation into a qualifier
Below the class to use to create your bean instances:
Note the
@Vetoed
annotation to make sure that CDI won't pick up this class to create a bean as we'll do it ourself. This class has to have a default constructor with no parameter to be used as class of a passivating bean (in application scoped)Then you need to declare the class of your custom bean. Sees it as a factory and metadata holder (scope, qualifiers, etc...) of your bean.
Note that the qualifier is the only parameter, allowing us to link the content of the qualifier to the instance in the
create()
method.Finally, you'll create the extension that will register your beans from a collection of injection points.
This extension is activated by adding its fully qualified classname to the
META-INF/services/javax.enterprise.inject.spi.Extension
text file.There are other way to create your feature with an extension, but I tried to give you a code working from CDI 1.0 (except for the
@Vetoed
annotation).You can find the source code of this extension in my CDI Sandbox on Github.
The code is quite straight forward, but don't hesitate if you have questions.