If you inject objects into itself in cdi, all interceptors are left out. That is a big difference to @EJB-Injection. In my project ejb-cdi-unit I try to simulate the injection of Ejbs by injecting them with CDI-means. Therefore I try to extend the already existing CDI-Extension by manipulating the InjectionTarget.
In the Web I found PropertyLoaderExtension as an example, how the InjectionTarget can be manipulated at the time when the actual injection occurs. The Propertymanipulating stuff I do not need, I am interested in activating the interceptors, when the proxy is called. To do that, I found, that the used Weld-Version provides two static functions in InterceptionDecorationContext. So I want to wrap each call through the injected field by calls to InterceptionDecorationContext. To do the actual wrapping I use the cglib-Enhancer.
public <T> void initializeSelfInit(final @Observes ProcessInjectionTarget<T> pit) {
final InjectionTarget<T> it = pit.getInjectionTarget();
InjectionTarget<T> wrapped = new InjectionTarget<T>() {
@Override
public void inject(final T instance, CreationalContext<T> ctx) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(instance.getClass());
enhancer.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
InterceptionDecorationContext.startIfNotEmpty();
try {
return method.invoke(instance, objects);
} catch (Throwable thw) {
if (thw instanceof InvocationTargetException) {
throw thw.getCause();
} else {
throw thw;
}
}
finally {
InterceptionDecorationContext.endInterceptorContext();
}
}
});
it.inject((T)enhancer.create(), ctx);
}
@Override
public void postConstruct(T instance) {
it.postConstruct(instance);
}
@Override
public void preDestroy(T instance) {
it.dispose(instance);
}
@Override
public void dispose(T instance) {
it.dispose(instance);
}
@Override
public Set<InjectionPoint> getInjectionPoints() {
return it.getInjectionPoints();
}
@Override
public T produce(CreationalContext<T> ctx) {
return it.produce(ctx);
}
};
pit.setInjectionTarget(wrapped);
}
As soon as the instance gets injected, the wrapping should be done and the wrapped object should be injected instead. When anybody calls a method at this wrapped object which happens to be a bean with intercepters, the weld-specific call to InterceptionDecorationContext should activate them. At another place in the code, where the Resource SessionContext is simulated, that works already fine. SessionContextSimulation
@Override
public <T> T getBusinessObject(Class<T> businessInterface) throws IllegalStateException {
Set<Bean<?>> beans = beanManager.getBeans(businessInterface);
if (beans.isEmpty() && businessInterface.getName().endsWith("_WeldSubclass")) {
beans = beanManager.getBeans(businessInterface.getSuperclass());
}
Bean<T> bean = (Bean<T>) beanManager.resolve(beans);
final Object testBean1 = beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(businessInterface);
enhancer.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
InterceptionDecorationContext.startIfNotEmpty();
try {
return method.invoke(testBean1, objects);
} catch (Throwable thw) {
if (thw instanceof InvocationTargetException) {
throw thw.getCause();
} else {
throw thw;
}
}
finally {
InterceptionDecorationContext.endInterceptorContext();
}
}
});
Object proxy = enhancer.create();
return (T) proxy;
}
But: initializeSelfInit gets called at the right place, the wrapper introduced by it gets called by Weld, but not during the call of the injected object. There must be a misunderstanding in that handling of the InterceptionTarget.