ProxyFactory sounds like a perfect solution indeed.
I now got something working, more or less, emphasis on less.
I first make a "normal" (but effectively dummy) decorator with @Priority available:
@Decorator
@Priority(PLATFORM_BEFORE + 200)
public abstract class HttpAuthenticationBaseDecorator implements HttpAuthenticationMechanism, Serializable {
private static final long serialVersionUID = 1L;
@Inject
@Delegate
HttpAuthenticationMechanism delegateMechanism;
@Override
public AuthStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthException {
return delegateMechanism.validateRequest(request, response, httpMessageContext);
}
// ...
}
Then I create a "dynamic/programmatic" decorator:
public class DynamicHttpAuthenticationDecorator implements Decorator<HttpAuthenticationBaseDecorator> {
private final Set<Type> types = new HashSet<Type>(asList(HttpAuthenticationBaseDecorator.class, Object.class));
private final Set<Type> decoratedTypes = singleton(HttpAuthenticationMechanism.class);
private final BeanManager beanManager;
private final InjectionPoint decoratorInjectionPoint;
private final Set<InjectionPoint> injectionPoints;
public DynamicHttpAuthenticationDecorator(BeanManager beanManager) {
decoratorInjectionPoint = new DecoratorInjectionPoint(
HttpAuthenticationMechanism.class,
beanManager.createAnnotatedType(HttpAuthenticationBaseDecorator.class).getFields().iterator().next(),
this);
injectionPoints = singleton(decoratorInjectionPoint);
this.beanManager = beanManager;
}
public HttpAuthenticationBaseDecorator create(CreationalContext<HttpAuthenticationBaseDecorator> creationalContext) {
return new AutoApplySessionDecorator(
(HttpAuthenticationMechanism) beanManager.getInjectableReference(decoratorInjectionPoint, creationalContext));
}
public void destroy(HttpAuthenticationBaseDecorator instance, CreationalContext<HttpAuthenticationBaseDecorator> creationalContext) {
creationalContext.release();
}
public Set<Type> getTypes() {
return types;
}
public Set<Type> getDecoratedTypes() {
return decoratedTypes;
}
public Class<?> getBeanClass() {
return HttpAuthenticationBaseDecorator.class;
}
public Type getDelegateType() {
return HttpAuthenticationMechanism.class;
}
public Set<InjectionPoint> getInjectionPoints() {
return injectionPoints;
}
}
This Decorator<T> "pretends" that it's for the dummy decorator, via the getTypes(), but in create() it returns another actual Decorator. Then I create the delegate injection point of that decorator by grabbing the @Delegate annotated field from the real decorator, wrapping that basically in an InjectionPoint and then using that later with beanManager#getInjectableReference.
Now after adding this via afterBeanDiscovery.addBean(new DynamicHttpAuthenticationDecorator(beanManager)), and it actually gets called at runtime (tested on Weld).
Disadvantages are a fixed priority and the fact that the dummy decorator is called as well.
Have to say that implementing the javax.enterprise.inject.spi.Decorator interface, especially the part for grabbing the @Delegate is quite non-obvious.
What do you think, is this guaranteed to work, or did I abuse the CDI APIs too much here?
Kind regards,
Arjan Tijms