Skip to content

Commit

Permalink
GH-972: Add new MLA.buildListenerArguments()
Browse files Browse the repository at this point in the history
Fixes #972

format code

sorry for skipping formation

format

blank format

fix method name

polymorphisms of method buildListenerArguments

deprecated buildListenerArguments and doc append

fix grammar

fix doc

fix SuppressWarnings position

fix Deprecated annotation

test case code improved

fix blank

fix link in comment

fix doc

fix name

improve doc

improve doc

*Polishing JavaDocs and Docs
  • Loading branch information
kc910521 authored and artembilan committed Apr 29, 2019
1 parent 0726a34 commit 8ac8ea1
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 7 deletions.
Expand Up @@ -117,6 +117,7 @@
* @author Dave Syer
* @author Gary Russell
* @author Greg Turnquist
* @author Cai Kun
*
* @see #setDelegate
* @see #setDefaultListenerMethod
Expand Down Expand Up @@ -288,7 +289,7 @@ else if (delegateListener instanceof MessageListener) {
}

// Invoke the handler method with appropriate arguments.
Object[] listenerArguments = buildListenerArguments(convertedMessage);
Object[] listenerArguments = buildListenerArguments(convertedMessage, channel, message);
Object result = invokeListenerMethod(methodName, listenerArguments, message);
if (result != null) {
handleResult(new InvocationResult(result, null, null), message, channel);
Expand Down Expand Up @@ -339,9 +340,29 @@ protected String getListenerMethodName(Message originalMessage, Object extracted
* @param extractedMessage the content of the message
* @return the array of arguments to be passed into the listener method (each element of the array corresponding to
* a distinct method argument)
* @deprecated use @{@link #buildListenerArguments(Object, Channel, Message)} to get complete arguments
*/
@Deprecated
protected Object[] buildListenerArguments(Object extractedMessage) {
return new Object[] {extractedMessage};
return new Object[] { extractedMessage };
}

/**
* Build an array of arguments to be passed into the target listener method. Allows for multiple method arguments to
* be built from message object with channel, More detail about {@code extractedMessage} in the method
* {@link #buildListenerArguments(java.lang.Object)}.
* This can be overridden to treat special message content such as arrays differently, and add argument in case of
* receiving Channel and original Message object to invoke basicAck method in the listener by manual acknowledge
* mode.
* @param extractedMessage the content of the message
* @param channel the Rabbit channel to operate on
* @param message the incoming Rabbit message
* @return the array of arguments to be passed into the listener method (each element of the array corresponding to
* a distinct method argument)
*/
@SuppressWarnings("deprecation")
protected Object[] buildListenerArguments(Object extractedMessage, Channel channel, Message message) {
return buildListenerArguments(extractedMessage);
}

/**
Expand Down Expand Up @@ -369,12 +390,11 @@ protected Object invokeListenerMethod(String methodName, Object[] arguments, Mes
}
else {
throw new ListenerExecutionFailedException("Listener method '" // NOSONAR lost stack trace
+ methodName + "' threw exception",
targetEx, originalMessage);
+ methodName + "' threw exception", targetEx, originalMessage);
}
}
catch (Exception ex) {
ArrayList<String> arrayClass = new ArrayList<String>();
ArrayList<String> arrayClass = new ArrayList<>();
if (arguments != null) {
for (Object argument : arguments) {
arrayClass.add(argument.getClass().toString());
Expand Down
@@ -1,4 +1,4 @@
/*
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -22,6 +22,7 @@
import static org.mockito.BDDMockito.willThrow;
import static org.mockito.Mockito.mock;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
Expand All @@ -30,6 +31,7 @@
import org.junit.Before;
import org.junit.Test;

import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Address;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
Expand All @@ -46,6 +48,7 @@
* @author Dave Syer
* @author Greg Turnquist
* @author Gary Russell
* @author Cai Kun
*
*/
public class MessageListenerAdapterTests {
Expand All @@ -64,15 +67,48 @@ public void init() {
this.adapter.setMessageConverter(new SimpleMessageConverter());
}

@Test
public void testExtendedListenerAdapter() throws Exception {
class ExtendedListenerAdapter extends MessageListenerAdapter {

@Override
protected Object[] buildListenerArguments(Object extractedMessage, Channel channel, Message message) {
return new Object[] { extractedMessage, channel, message };
}

}
MessageListenerAdapter extendedAdapter = new ExtendedListenerAdapter();
final AtomicBoolean called = new AtomicBoolean(false);
Channel channel = mock(Channel.class);
class Delegate {

@SuppressWarnings("unused")
public void handleMessage(String input, Channel channel, Message message) throws IOException {
assertThat(input).isNotNull();
assertThat(channel).isNotNull();
assertThat(message).isNotNull();
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
called.set(true);
}

}
extendedAdapter.setDelegate(new Delegate());
extendedAdapter.containerAckMode(AcknowledgeMode.MANUAL);
extendedAdapter.onMessage(new Message("foo".getBytes(), messageProperties), channel);
assertThat(called.get()).isTrue();
}

@Test
public void testDefaultListenerMethod() throws Exception {
final AtomicBoolean called = new AtomicBoolean(false);
class Delegate {

@SuppressWarnings("unused")
public String handleMessage(String input) {
called.set(true);
return "processed" + input;
}

}
this.adapter.setDelegate(new Delegate());
this.adapter.onMessage(new Message("foo".getBytes(), messageProperties), null);
Expand All @@ -83,11 +119,13 @@ public String handleMessage(String input) {
public void testAlternateConstructor() throws Exception {
final AtomicBoolean called = new AtomicBoolean(false);
class Delegate {

@SuppressWarnings("unused")
public String myPojoMessageMethod(String input) {
called.set(true);
return "processed" + input;
}

}
this.adapter = new MessageListenerAdapter(new Delegate(), "myPojoMessageMethod");
this.adapter.onMessage(new Message("foo".getBytes(), messageProperties), null);
Expand Down Expand Up @@ -163,7 +201,7 @@ public void testReplyRetry() throws Exception {
Channel channel = mock(Channel.class);
RuntimeException ex = new RuntimeException();
willThrow(ex).given(channel)
.basicPublish(eq("foo"), eq("bar"), eq(Boolean.FALSE), any(), any());
.basicPublish(eq("foo"), eq("bar"), eq(Boolean.FALSE), any(), any());
Message message = new Message("foo".getBytes(), this.messageProperties);
this.adapter.onMessage(message, channel);
assertThat(this.simpleService.called).isEqualTo("handle");
Expand Down Expand Up @@ -205,4 +243,5 @@ public String notDefinedOnInterface(String input) {
}

}

}
30 changes: 30 additions & 0 deletions src/reference/asciidoc/amqp.adoc
Expand Up @@ -1705,6 +1705,36 @@ new MessageListenerAdapter((ReplyingMessageListener<String, String>) data -> {
----
====

Starting with version 2.2, the `buildListenerArguments(Object)` has been deprecated and new `buildListenerArguments(Object, Channel, Message)` one has been introduced instead.
The new method helps listener to get `Channel` and `Message` arguments to do more, such as calling `channel.basicReject(long, boolean)` in manual acknowledge mode.
The following listing shows the most basic example:

====
[source,java]
----
public class ExtendedListenerAdapter extends MessageListenerAdapter {
@Override
protected Object[] buildListenerArguments(Object extractedMessage, Channel channel, Message message) {
return new Object[]{extractedMessage, channel, message};
}
}
----
====

Now you could configure `ExtendedListenerAdapter` as same as `MessageListenerAdapter` if you need to receive "`channel`" and "`message`".
Parameters of listener should be set as `buildListenerArguments(Object, Channel, Message)` returned, as the following example of listener shows:

====
[source,java]
----
public void handleMessage(Object object, Channel channel, Message message) throws IOException {
...
}
----
====

====== Container

Now that you have seen the various options for the `Message`-listening callback, we can turn our attention to the container.
Expand Down
5 changes: 5 additions & 0 deletions src/reference/asciidoc/whats-new.adoc
Expand Up @@ -19,3 +19,8 @@ See <<data-projection>> for more information.

The Log4J and Logback `AmqpAppender` s now support a `verifyHostname` SSL option.
See <<logging>> for more information.

===== MessageListenerAdapter Changes

The `MessageListenerAdapter` provides now a new `buildListenerArguments(Object, Channel, Message)` method to build an array of arguments to be passed into target listener and an old one is deprecated.
See <<message-listener-adapter>> for more information.

0 comments on commit 8ac8ea1

Please sign in to comment.