Search code examples
javajbosscdi

Producer for dynamic instance not getting annotation


I am having a producer class that looks like this:

public class HostConfigPropertyProducer {
    @Any
    @Inject
    Instance<String> baseUriInstance;

    @Produces
    @HostConfigProperty
    String produce(InjectionPoint ip) {
        HostConfigProperty property =  ip.getAnnotated().getAnnotation(HostConfigProperty.class);
        Instance<String> baseUriCandidate = baseUriInstance.select(new StringPropertyLiteral(property.key()));
        return baseUriCandidate.get();
    }
}

The StringPropertyLiteral is looking like this:

public final class StringPropertyLiteral extends AnnotationLiteral<StringProperty> implements StringProperty {
    private final String keyValue;

    public StringPropertyLiteral(String key) {
        keyValue = key;
    }

    @Override
    public String key() {
        return keyValue;
    }

    @Override
    public String defaultValue() {
        return "";
    }
}

Now there is also a @Produces for StringProperty that I am trying to invoke using my select(new StringP...). It correctly goes into that producer but the problem is that it is not able to get a StringProperty annotation in that code.

More specifically that means that in the following code it gets null:

@Produces
@StringProperty
public String stringProperty(InjectionPoint ip) {
    StringProperty property = ip.getAnnotated().getAnnotation(StringProperty.class);
    return property.defaultValue();
}

The getAnnotation is returning null and inspecting it in the debugger shows that it only has 2 annotations, the Any and the Inject annotation. Also in the qualifiers of the injection point I can find only one qualifier, thats Any

Why is my annotation literal not being passed to the producer? I have used a similar pattern in another context but there the target for select was a type, that was not obtained by a producer and it worked.


Solution

  • The confusion here is how the InjectionPoint works. When you make a dynamic select (Instance#select()), it will not create a new injection point. It will still refer to the original injection point you had. E.g. in your second producer you do this:

    public String stringProperty(InjectionPoint ip) {
       StringProperty property = ip.getAnnotated().getAnnotation(StringProperty.class);
    

    However, the injection point you get here will be the original one:

    @Any
    @Inject
    Instance<String> baseUriInstance;
    

    And as such, this IP does not have the annotation you request (StringProperty), hence the null value.

    This simply won't work and you will need to work around it. I would probably need to see more of your code to help you with it. It seems as a kind of unusual design to chain producer calls like this.