Search code examples
cdiwildfly-swarmweld2

Are Functions special in CDI w.r.t. @Inject vs BeanManager.getBeans(Function.class)?


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;
        }
    });

Solution

  • 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.