I have two classes, which I wish to inject:
@ApplicationScoped
public class BeanThing {
public String apply(String s) {
return "bt(" + s + ")";
}
}
and
@ApplicationScoped
public class ClassFunction implements Function<String, String> {
@Override
public String apply(String s) {
return "cf(" + s + ")";
}
}
When I try and use them elsewhere I get different behaviour:
Set<Bean<?>> functions = beanManager.getBeans(Function.class);
for (Bean<?> untyped : functions) {
Bean<Function<String, String>> typed = (Bean<Function<String, String>>) untyped;
Function<String, String> function = beanManager.getContext(typed.getScope()).get(typed, beanManager.createCreationalContext(typed));
System.err.println(function.apply("beanManager"));
}
Set<Bean<?>> beanThings = beanManager.getBeans(BeanThing.class);
for (Bean<?> untyped : beanThings) {
Bean<BeanThing> typed = (Bean<BeanThing>) untyped;
BeanThing beanThing = beanManager.getContext(typed.getScope()).get(typed, beanManager.createCreationalContext(typed));
System.err.println(beanThing.apply("beanManager"));
}
System.err.println(injectedFunction.apply("injected"));
System.err.println(beanThing.apply("injected"));
System.err.println("injectedFunction is a function: " + (injectedFunction instanceof Function));
my output is:
bt(beanManager)
cf(injected)
bt(injected)
injectedFunction is a function: true
which is one fewer lines than I expect.
Could someone explain what going on here?
Solution, thanks to Siliarus for setting me off down the right path:
Set<Bean<?>> functions = beanManager.getBeans(new ParameterizedType() {
@Override
public Type[] getActualTypeArguments() {
return new Type[]{new WildcardType() {...}, new WildcardType() {...};
}
@Override
public Type getRawType() {
return Function.class;
}
});
If I get your sample correctly what you are missing is the first line - output from the Function
when obtained via BeanManager
.
My guess is, that the Set<Bean<?>> functions
is empty. The reason for that are generics. Function
is a generic type and methods on BeanManager
are not really good with that. CDI spec defines Typesafe resolution for parameterized types pretty well (although it takes some reading).
In short, your bean of type Function<String, String>
won't be assignable to just raw Function.class
, which you pass to BeanManager
method.
As a side note, if you wish to instantiate parametrized types on-the-fly, you can always use Instance<T>
, which supports the use of TypeLiteral
- a special construct which holds not only the raw type, but also information about the actual parameters.