smallrye-reactive-messaging icon indicating copy to clipboard operation
smallrye-reactive-messaging copied to clipboard

Mediator instantiation may result in AmbiguousResolutionException

Open mkouba opened this issue 7 years ago • 6 comments

This may happen if class hierarchies are in use:

@ApplicationScoped
class Foo {
  @Incoming("source")
  @Outgoing("processed-a")
  public String toUpperCase(String payload) {
    return payload.toUpperCase();
  }
}
@ApplicationScoped
class Bar extends Foo {
}

In this particular case, there are two beans Foo with bean types [Foo,Object] and qualifiers [Default] and Bar with bean types [Bar,Foo,Object] and qualifiers [Default]. So if MediatorManager does instance.select(Foo.class, []).get() => AmbiguousResolutionException.

In theory, you could store the Bean<> object in mediator config but then you would have to switch to BeanManager methods (getReference() etc.). Another possibility is to forbid class hierarchies.

mkouba avatar Nov 23 '18 07:11 mkouba

What would be the "CDI" way of handling this situation?

cescoffier avatar Nov 27 '18 11:11 cescoffier

Well, the "correct" way would be to handle the class hierarchies correctly, which is not an easy thing to do. I.e. you would have to filter out beans that override the annotated method:

@ApplicationScoped
class Foo {
  @Incoming("source")
  @Outgoing("processed-a")
  public String toUpperCase(String payload) {
    return payload.toUpperCase();
  }
}
@ApplicationScoped
class Bar extends Foo {
 public String toUpperCase(String payload) { }
}

In this case, ProcessManagedBean.getAnnotatedBeanClass().getMethods() for Bar would return two AnnotatedMethods with the name toUpperCase() and you would have to use AnnotatedMethod.getJavaMember().getDeclaringClass() to determine the type in the type hierarchy that declared the method.

And as I said in the previous comment - you can store a reference to the Bean<> and then use BeanManager.getReference() to obtain a bean instance.

mkouba avatar Nov 27 '18 11:11 mkouba

And as I said in the previous comment - you can store a reference to the Bean<> and then use BeanManager.getReference() to obtain a bean instance.

I think what Martin meant is that every MediatorConfiguration would carry an information about Bean<T> instead of the class of that bean. Based on that you can replace bean retrieval process you have (using Instance.select()) with one via BeanManager.getReference(). That way you can get reference to the correct bean even with hierarchy in place (as both Foo and Bar have different Bean<T> metadata).

@mkouba in such case you will have to care about all the CreationalContexts you create, right? E.g. keep a reference to them and them perform release() once you no longer need those beans.

manovotn avatar Nov 27 '18 13:11 manovotn

I think what Martin meant is that every MediatorConfiguration would carry an information about Bean<T> instead of the class of that bean.

Exactly.

@mkouba in such case you will have to care about all the CreationalContexts you create...

Exactly.

And there's probably more...

mkouba avatar Nov 27 '18 13:11 mkouba

I believe that we should just not support inheritance for now until we get a better / good answer.

cescoffier avatar Dec 03 '18 07:12 cescoffier

+1 and make sure it's documented.

mkouba avatar Dec 03 '18 08:12 mkouba