I have a strange situation that I don't understand. I would like to decide in a bean, should I enable or disable the SQS listener. So I've created a config class with a definition:
@Bean
MyListener createListener(Features f){
return f.shouldListen() ? new RealListener() : new MockListener();
}
As you can see, I have such an inheritance:
interface MyListener{}
class RealListener implements MyListener{
@SqsListener(...)
list handleMessage(SqsMessage message){
...
}
}
class MockListener implements MyListener{}
Now, the funny part:
It sometimes works.
After few restarts of the application, the handleMessage() method is called but in most cases it isn't without any exception. The queue is created, all permissions are in place.
To make it working I need to return RealListener from createListener() method or move @SqsListener annotation to a method in the MyListener interface. Both are not options for me, because I don't want to call AWS, when the mock is enabled.
I've tried with conditional bean creation but as Features depends on a DB (indirect entityManager dependency, to be more precise), I can't make it working. I've tried with abstract class instead of interface, but without luck. I've tried to register the RealListener bean in the BeanFactoryPostProcessor but this also doesn't work (same entityManager dependency issue). I've tried to move the annotation to the interface and use @ConditionalOnBean with @Primary to create an empty AmazonSqsClient when the mock is enabled, but it doesn't work.
I could understand that it doesn't work, because the bean has to be created for a type with the method annotated with @SqsListener (not with it's supperclass/interface type), but I have three such beans and a lottery - sometimes all work, sometimes one or two but sometimes none of those.
Do you have any suggestions?
Well... I've found the issue but it still would be nice, to know, what has happened.
So... There is a class
QueueMessageHandlerusingdetectHandlerMethods(...)method from the superclassAbstractMethodMessageHandler. This method usesMethodIntrospector.selectMethods()to select methods to scan. This class takes into consideration methods annotated with@SqsListenerwhen there is@EnableSqsin some configuration class. The problem is, in my project the@EnableSqsannotation is located in some file - not the file withcreateListener(...)method and not the main class of the Spring Boot application. That means, the class with@EnableSqscan be loaded before or afterMethodIntrospector.selectMethods().The output is:
@EnableSqsto the main class of the project