[cdi-dev] Destroying beans from an interceptor

Jozef Hartinger jharting at redhat.com
Wed Nov 12 13:49:51 EST 2014


Hi Arjan,

there is a bug in Weld (WELD-1785) preventing this from working which is 
going to be fixed in the next release. What you are doing should work 
IMO as long as the interceptor does not call any other methods on the 
target instance. In addition it must count with the target instance 
being destroyed within the instance.destroy() call.

Perhaps a nicer way of doing this would be:

@Inject
@Intercepted
private Bean<?> bean;

         Context context = manager.getContext(bean.getScope());
         if (!(context instanceof AlterableContext)) {
             throw new IllegalStateException("Context does not support 
removal of instances");
         }
         AlterableContext alterableContext = 
AlterableContext.class.cast(context);
         alterableContext.destroy(bean);

On 11/10/2014 02:59 PM, arjan tijms wrote:
> Hi,
>
> I wonder if it would be allowed according to the CDI spec to destroy a
> bean instance from within an interceptor.
>
> To test this (on Weld) I used the following code:
>
> @Interceptor
> @DestroyOnError
> @Priority(APPLICATION)
> public class DestroyOnErrorInterceptor implements Serializable {
>
>      private static final long serialVersionUID = 1L;
>
>      @AroundInvoke
>      public Object tryInvoke(InvocationContext ctx) throws Exception {
>
>          try {
>              return ctx.proceed();
>          } catch (Exception e) {
>              destroy(ctx.getMethod().getDeclaringClass());
>              throw e;
>          }
>      }
>
>      private <T> void destroy(Class<T> clazz) {
>          Instance<T> instance = CDI.current().select(clazz);
>          instance.destroy(instance.get());
>      }
>
> }
>
>
> When I use this interceptor on a SessionScoped bean:
>
> @SessionScoped
> public class TestBean implements Serializable {
>
>      private static final long serialVersionUID = 1L;
>
>      @DestroyOnError
>      public void test() {
>          throw new IllegalStateException();
>      }
> }
>
> And then inject said bean in say a Servlet and call the test() method,
> destruction of the bean happens partially, but as soon as Weld tried
> to invocate a preDestroy method, it goes through the bean proxy again,
> detects that "the" interceptor handler is already active, promptly
> skips its attempt to call a preDestroy method and then to add insult
> to injury tries to call a "proceed" method which is always null and
> thus throws a NPE.
>
> (this happens in
> org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke)
>
> I tried some alternative methods to destroy the bean such as:
>
>
> Bean<T> bean = resolve(beanManager, beanClass);
>
> AlterableContext context = (AlterableContext)
> beanManager.getContext(bean.getScope());
> context.destroy(bean);
>
> with resolve being:
>
> public static <T> Bean<T> resolve(BeanManager beanManager, Class<T> beanClass) {
>          Set<Bean<?>> beans = beanManager.getBeans(beanClass);
>
>          for (Bean<?> bean : beans) {
>              if (bean.getBeanClass() == beanClass) {
>                  return (Bean<T>)
> beanManager.resolve(Collections.<Bean<?>>singleton(bean));
>              }
>          }
>
>          return (Bean<T>) beanManager.resolve(beans);
>      }
>
> But this resulted in the same problem.
>
> Any idea?
>
> Kind regards,
> Arjan Tijms
> _______________________________________________
> cdi-dev mailing list
> cdi-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/cdi-dev
>
> Note that for all code provided on this list, the provider licenses the code under the Apache License, Version 2 (http://www.apache.org/licenses/LICENSE-2.0.html). For all other ideas provided on this list, the provider waives all patent and other intellectual property rights inherent in such information.



More information about the cdi-dev mailing list