The easiest way to do let CDI to manage your class is to use a producer.
public class MyProducers {
@Produces
@RequestScoped //Could be any scope here
@FromReflection //a qualifier to distinguish this Bean of type Object from others. Would be better to have a more specific bean type if all your class come from the same ancestor.
public Object produceMyClass()
{
String clazz = "org.myorg.thisIsMyClass";
Object myObject = Class.forName(clazz).newInstance();
return myObject;
}
}
Somewhere else in your code you can use this producer like this :
@Inject
@FromReflection
Object myBean;
** Edit : adding InjectionPoint
usage. **
Now you can enhance your producer by injecting it's InjectionPoint
in its parameter list. You can then use the metadata of the injection point (i.e qualifier) to dynamically find your class.
First you have to add a field to store the class name in your @FromReflection
qualifier :
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
@Documented
public @interface FromReflection {
@Nonbinding String value(); // classname will be store here
}
then you use this info in your producer :
public class MyProducers {
private String extractClassName(InjectionPoint ip) {
for (Annotation annotation : ip.getQualifiers()) {
if (annotation.annotationType().equals(FromReflection.class))
return ((FromReflection) annotation).value();
}
throw new IllegalStateException("No @FromReflection on InjectionPoint");
}
@Produces
@FromReflection
public Object produceMyClass(InjectionPoint ip)
{
String clazzNanme = extractClassName(ip);
Object myObject = Class.forName(clazz).newInstance();
return myObject;
}
}
Note that the produced bean has to be in @Dependent
scope, it's a constraint when injecting InjectionPoint
in the producer parameters.
You can now inject your bean like that :
@Inject
@FromReflection("org.myorg.thisIsMyClass")
Object myBean;
Now if you want to decide at runtime which class you want to build, you'll have to use the CDI programmatic lookup feature which allow you to create synthetic qualifier.
First create an AnnotationLiteral for your qualifier to be able to instantiate a a new qualifier.
public class FromReflectionLiteral extends AnnotationLiteral<FromReflection> implements FromReflection {
private String value;
public FromReflectionLiteral(String value) {
this.value = value;
}
@Override
public String value() {
return value;
}
}
Then you'll use the Instance<>
bean to request for your final bean.
public class ConsumingBean {
@Inject
@Any
Instance<Object> myBeanInstance;
public Object getBeanFor(String className) {
return myBeanInstance.select(new FromReflectionLiteral(className)).get();
}
...
}
Next step would be to use a portable extension...