Injecting a service in the RabbitMQ - ConfirmCallback class is not working - spring-rabbit

I have created a separate callback class implementing ConfirmCallback interface and overridden the confirm(). Corrlation data and ack is working fine. But I have injected using #Autowired a service to do some other activities after successful ack from the rabbitMQ. But that service reference is not injected at all. I have injected the same service in other classes it works fine. My code
public MyConfirmCallback implements ConfirmCallback {
#Autowired
private PostAckService postAckService;
public void confirm(CorrelationData correlationData, Boolean ack){
//check the ack and verify the correlationdata.
postAckService.clearData(....);
}
}
postAckService is throwing nullpointer exception. Any idea ?

MyConfirmCallback has to be a bean in the application context for auto wiring to work. You can't simply use new MyConfirmCallback() in your application.
If you believe it's a bean, turn on DEBUG logging for org.springframework; it emits lots of information about bean creation.

Related

Unit test - Problems testing #Retryable and #Recover

I have a component that's using #Retryable annotation and another service using that component. So I'm trying to test that the component using #Retryable annotation is actually retrying.
I've tried every solution there is on the web right now but nothing worked for me. I'm trying to create a unit test for this and not integration test. So far I've managed to get to the exception that's supposed to be thrown and #Retryable wasn't even retrying, the method just threw the exception and thats it.
This is the component using Retryable annotation:
#Component
public class OurComponent {
#Retryable(maxAttempts = 10,
backoff = #Backoff(delay = 2000),
value = {someException.class}
)
public void someMethod(SomeObject someObject) throws someException {
Object createObject = anotherMethod(someObject); //this method throws someException
...
}
}
And the service using this ourComponent:
#Service
public class someService {
private final OurComponent ourComponent;
public SomeService(OurComponent ourComponent) {
this.ourComponent = ourComponent;
}
...
public void methodUsingComponent() {
SomeObject someObject = new SomeObject(args);
ourComponent.someMethod(someObject);
}
}
Now I've tried to #InjectMocks and #MockBean this service and component but it still didn't work. Is it even possible to test #Retryable annotation without doing integration test?
If you use a unit test that doesn't use spring at all, you won't be able to test it easily.
This is due to the fact that annotations like this are recognized by spring and the corresponding bean is wrapped with a runtime-generated proxy that implements the "retry" logic.
Now, if you don't have spring who triggers all this mechanism, this #Retryable annotation is basically useless, mockito doesn't know anything about, so is Junit.
You could try to create a proxy like this manually (check what logic spring-retry invokes) but it looks to be an overkill. And frankly speaking, it doesn't give you anything. Unit test should check the functionality of your code and not the logic behind spring retry that was implemented by somewhere else and tested.

why can't spring find the #Source bean channel created by spring cloud stream?

I'm trying to use Spring Cloud Stream to publish and consume Kafka messages. I've been working off of the documentation here on Accessing Bound Channels. I'm trying to use a custom name on the channel for my topic, so I have a #Qualifier when I'm trying to inject it, but spring can't find the relevant bean. It says "For each bound interface, Spring Cloud Stream will generate a bean that implements the interface", but the auto-wiring isn't working.
The error I'm getting is "Parameter 0 of constructor in com...MessagingManager required a bean of type 'org.springframework.messaging.MessageChannel' that could not be found."
I tried using #Autowired before the MessagingManager constructor like in the example, but then got a similar error in bean factory about there being 2 of them, so I took it out, and got the current error.
It's probably complicated by my trying to use a Processor.
Here are my components. I'm running it with spring boot and trying to test it with this :
#Component
public class StartupTester implements ApplicationListener<ContextRefreshedEvent> {
MessagingManager messagingManager;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
messagingManager.sendThingCreatedMessage(new ThingCreated("12345", "667788"));
}
}
#Component
public class MessagingManager {
private MessageChannel thingCreatedChannel;
public MessagingManager(#Qualifier(ThingChannelProcessor.THING_CREATED) MessageChannel output) {
thingCreatedChannel = output;
}
public void sendThingCreatedMessage(ThingCreated thingCreated) {
thingCreatedChannel.send(MessageBuilder.withPayload(thingCreated).build());
}
}
#Component
public interface ThingsChannelProcessor extends Processor {
String THING_REQUEST = "thing-request";
String THING_CREATED = "thing-created";
#Input(THING_REQUEST )
SubscribableChannel thingsRequest();
#Output(THING_CREATED )
MessageChannel thingCreated();
}
And I also have #EnableBinding(ThingsMessagingManager.class) on my main class which is annotated with #SpringBootApplication.
I could not reproduce your error. But I have a few points you could follow:
You don't need to annotate the interface with #Component
It seems that you have a typo on your #EnableBinding you should have #EnableBinding(ThingsChannelProcessor.class) not ThingsMessagingManager
You don't need to extend Processor either, that may be the reason why you got 2 beans in the first time. If you are customizing your channels, you don't need to descend from Sink/Source/Processor, look at the Barista example in the docs
Listen for an contextRefresh won't work either, as we do the binding after the context was refreshed
Actually, let me a bit more clear on 4. We create a child context, so in order to make sure that your context has fully initialized, make sure you also implement ApplicationContextAware on your Starter, and before sending the message check if the contexts are the same otherwise you will get an error if(this.context.equals(event.getApplicationContext()))

Sending a message to a specific client with Spring Websockets

So I've got a Runnable class that should invoke the method notifyUser(String username, String content) once a certain criteria is met. I've been trying to get this to work but it always fails with NullPointerExceptions. This has most likely to do with an Autowiring failure (since the Runnable class is not managed by Spring). Autowiring SimpMessagingTemplate in a Spring-managed context works just fine and the methods do what they're supposed to.
What I want to do is to invoke the method (or a similar method) convertAndSendToUser of the SimpMessagingTemplate, but I cannot autowire it in this context. Everything I've tried failed so far, which is why I assume I got some of the basic concepts wrong.
My Configuration looks like this:
#Configuration
#EnableScheduling
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/test");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/test").withSockJS();
}
}
Update: I've managed to get rid of the NullPointerException by using the following code .. but messages (convertAndSendToUser() as well as convertAndSend()) don't get picked up by the client. The developer console doesn't show any incoming messages.
AbstractApplicationContext ctx = new AnnotationConfigApplicationContext(Application.class);
ctx.getAutowireCapableBeanFactory().autowireBean(myService);
That's true because you do this:
new AnnotationConfigApplicationContext(Application.class);
in that your class, meaning starting a new full appicationContext. But your user is registered in the another context.
It isn't clear why you can't make your component managed by Spring, but there is no other way to use SimpMessagingTemplate, if you can't reach applicationContext.
It would be better to share that your code to investigate from our side and decide how can we help there.
Maybe you can use there WebApplicationContextUtils...

Scheduled Tasks in Liferay with Autowired

im trying to create scheduled task in liferay portlet.
Liferay: 6.2
Spring: 3.1.4.RELEASE
With
<scheduler-entry>
<scheduler-description>test-scheduler</scheduler-description>
<scheduler-event-listener-class>
project.ScheduledProcesser
</scheduler-event-listener-class>
<trigger>
<simple>
<simple-trigger-value>
1
</simple-trigger-value>
<time-unit>minute</time-unit>
</simple>
</trigger>
</scheduler-entry>
and the corrensponding class
#Component
public class ScheduledProcesser implements MessageListener {
private static Log log = LogFactoryUtil
.getLog(ScheduledProcesser.class);
#Autowired
#Qualifier("myRequestService")
private RequestService service;
#Override
public void receive(Message message) throws MessageListenerException {
log.info("Starting");
Request req = service.get("AAA746");
if (req!=null)
log.info("REQ -" + req.getId());
log.info("Finished");
}
The method is firing. But the service component is null. Normally is the service in other parts working well.
I have tried to find the solution, but maybe there is some settings missing.
Thanx,
MessageListener is not instantiated by Spring, but by Liferay (see the implementation of QuartzSchedulerEngine.getMessageListener(String, ClassLoader)). And Liferay just instantiates the class. So you can't autowire anything into a MessageListener that is defined in the liferay-portlet.xml.
But you could use PortalBeanLocatorUtil.locate instead, if your service is defined in the portal application context.

Event Listeners in spring is called twice

I am an issue with Spring Event Listeners In my Web app, Any immediate help will be appreciated.
Event Listeners is registered and called twice, If I have cyclic dependency.
I have service class, this has #transaction annotation on another methods
#Service(PBSTaskService.BEAN_NAME)
public class PBSTaskServiceImpl extends StandardServiceImpl<ITask> implements PBSTaskService,ApplicationListener<SurveyDefinitionPublishedEvent>
{
#Autowired
private AutoSelectTaskSliceRouteSyncService autoSelectTaskSliceRouteSyncService; // CYCLIC Dependency
#Override
public void onApplicationEvent(SurveyDefinitionPublishedEvent event)
{
System.out.println("PBSTSImpl"); // THIS IS CALLED TWICE
}
... Other method with #Transaction Annotation
}
#Service(AutoSelectTaskSliceRouteSyncService.BEAN_NAME)
public class AutoSelectTaskSliceRouteSyncServiceImpl implements AutoSelectTaskSliceRouteSyncService
{
#Autowired private PBSTaskService pbsTaskService; // CYCLIC dependency
}
Now If I remove AutoSelectTaskSliceRouteSyncService dependency from First Class, OnApplicationEvent is called once, else twice.
I debugged and found out that
SimpleApplicationEventMulticaster.getApplicationListeners(myEvent) : Has two proxy object, one wrapped with Cglib and another default one. But it has two only in case if it has cyclic dependency. If I remove Cyclic dependency, it has only one proxy object and that one is enahnces by CGLIB.
my Tx annotation :
I had tried it with proxy-target-class="true or false" but no luck.
You may want to have a look on
https://jira.springsource.org/browse/SPR-7940?focusedCommentId=98988&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-98988
Since Spring 4.2 you can do away with implementing ApplicationListener and use the new #EventListener annotation on methods in any managed bean. This should help you avoid any conflicts.
Below is an example from https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2
#Component
public class MyListener {
#EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
...
}
}
ApplicationEvent Listeners are called twice at many more places in our web app. This is one of scenarios that we caught up.
Reason :
Listeners are registered twice. Two proxy are returned wrapped over one instance of listeners. Proxy returned are 1. Dynamic Jdk Interface proxy 2. Cglib Proxy, when we have #transactions annotations.
To recreate these three point are must:
Your listeners must implements ApplicationListener 2. Your listeners must have cyclic dependency with another class 3.Your listeners must have one method annotated with #Transaction.
I have created a separate project where I am able to reproduce it with spring and hibernate. If 2 and 3 are not present together, then we are safe.
Solution
I tried many tweaks with spring and transaction configuration but no luck. Then finally with my demo project when I moved the transaction code to another class, so that the listeners do not have any #transaction annotations then it worked for me.
In Spring classes anotated with #Service or #Component which implement the ApplicationListener interface are going to receive duplicate events. To resolve the issue, to only receive single events, just remove the #Service or #Compontent annotation.
In a case of circular dependency between Spring beans, Spring Beans machinery might (under certain circumstances) place two versions of a same bean, the bean itself and its Advised wrapper into the list of ApplicationListeners handled by an ApplicationEventMulticaster.
You could, however, implement your custom ApplicationEventMulticaster and fix this bug (it looks like a bug to me).
In a snippet below a custom implementation subclasses Spring's SimpleApplicationEventMulticaster, ignores non-Advised duplicate of a bean, and leaves Advised version of it in the list of ApplicationListeners (most likely you would want an Advised version of your onApplicationEvent method to be called - in a case it is annotated with #Transactional or AOP-advised, but if you need otherwise, the change of algorithm is trivial)
#Component
public class AdviceAwareApplicationEventMulticaster extends SimpleApplicationEventMulticaster {
#Override
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
Map<ApplicationListener<?>, ApplicationListener<?>> listenersByNakedInstances = new LinkedHashMap<>();// because superclass returns sorted listeners
Collection<ApplicationListener<?>> applicationListeners = super.getApplicationListeners(event, eventType);
for (ApplicationListener<?> listener : applicationListeners) {
boolean advised = false;
ApplicationListener<?> nakedListener = null;
if (listener instanceof Advised) {
try {
nakedListener = (ApplicationListener<?>) ((Advised)listener).getTargetSource().getTarget();
} catch (Exception e) {
// TODO
}
advised = true;
} else
nakedListener = listener;
if (advised || !listenersByNakedInstances.containsKey(nakedListener))
listenersByNakedInstances.put(nakedListener, listener);
}
return listenersByNakedInstances.values();
}
}
You don't need to anyhow make your custom implementation known to Spring, it's enough to have it as a Spring bean and Spring Application Context will pick it up.
Also, don't forget that if there are more one Spring Application Contexts in the application, your Listener might be called for each of those, but it's altogether different story.
I was running into the same issue with one of my services, created another listner with the same event that was only called once.
So what #SimonH wrote is not always the case, only in some circumstances I could not reproduce:
In Spring classes anotated with #Service or #Component which implement the ApplicationListener interface are going to receive duplicate events.
In my case this lead to a double call of the onApplicationEvent method.
#Service
public class TestClass implements ApplicationListener<MyEvent>{
#Override
public void onApplicationEvent(MyEvent event){
// called twice
}
}
Instead of the code above, I could solve it by creating the Event Listener as an inner class and then call the event method of the parent.
#Service
public class TestClass {
#Component
private class MyListener implements ApplicationListener<MyEvent> {
#Override
public void onApplicationEvent(MyEvent event) {
TestClass.this.onApplicationEvent(event);
}
}
public void onApplicationEvent(MyEvent event){
//Have fun with a single event here
}
}

Resources