How can I handle multiple disposal methods for inherited types?

234 views Asked by At

I have two classes.

class A {
}

class B extends A {
}

And in my producer class I declared like this.

@Produces A produceA(InjectionPoint ip) {
    return new A();
}

void disposeA(@Disposes A a) {
    // empty
}

@Produces B produceB(InjectionPoint ip) {
    return new B();
}

void disposeB(@Disposes B b) {
    // empty
}

And Weld complains.

....DefinitionException: WELD-000077: Cannot declare multiple disposal methods for this producer method.

Producer method:  org.jboss.weld.bootstrap.BeanDeployer@41e68d87
Disposal methods:  
  - Disposer method [[BackedAnnotatedMethod] ....Producer.disposeA(@Disposes A)],
  - Disposer method [[BackedAnnotatedMethod] ....Producer.disposeB(@Disposes B)]

Is this normal? How can I solve it?

1

There are 1 answers

0
Siliarus On BEST ANSWER

This is a typesafe resolution matter and it works as intended. From the specification, 3.4.3. Disposer method resolution:

A disposer method is bound to a producer method or producer field if:

  • the producer method or producer field is declared by the same bean class as the disposer method, and
  • the producer method or producer field is assignable to the disposed parameter, according to the rules of typesafe resolution defined in Typesafe resolution (using Assignability of raw and parameterized types).

In your specific case, you have the producer method produceB which creates a bean whose types are going to be {B, A, Object}. The types are derived from the return type and will contain the type itself, all super classes and all implemented interfaces (as stated here in CDI spec).

You then have two disposer methods, one with the disposer parameter A, the other with B. You can think of those parameters as injection points if that helps - your produceB producer method creates a bean that fits both of these disposers hence creating ambiguity because Weld needs at most one disposer method for each bean.

If you want to read more in how exactly typesafe resolution works, look here.

As for how to "solve" this situation, I can think of two approaches from the top of my head (there is likely more ways to do this):

  • You can declare each producer + disposer in another bean. According to specification, disposer needs to be declared in the same bean where producer is, so that would eliminate this issue.
  • You can use @Typed on the producer and limit the types of produceB to only B.class which should resolve this situation as well but the bean will no longer be eligible for injection into any injection point with type A.