Merge pull request #799 from garyrussell/INT-3002
* INT-3002: Fix Content-Type Mapping
This commit is contained in:
@@ -231,12 +231,11 @@ public class AmqpOutboundEndpoint extends AbstractReplyProducingMessageHandler
|
||||
}
|
||||
|
||||
private Message<?> sendAndReceive(String exchangeName, String routingKey, Message<?> requestMessage) {
|
||||
// TODO: add a convertSendAndReceive method that accepts a MessagePostProcessor so we can map headers?
|
||||
Assert.isTrue(amqpTemplate instanceof RabbitTemplate, "RabbitTemplate implementation is required for send and receive");
|
||||
MessageConverter converter = ((RabbitTemplate) this.amqpTemplate).getMessageConverter();
|
||||
MessageProperties amqpMessageProperties = new MessageProperties();
|
||||
this.headerMapper.fromHeadersToRequest(requestMessage.getHeaders(), amqpMessageProperties);
|
||||
org.springframework.amqp.core.Message amqpMessage = converter.toMessage(requestMessage.getPayload(), amqpMessageProperties);
|
||||
this.headerMapper.fromHeadersToRequest(requestMessage.getHeaders(), amqpMessageProperties);
|
||||
org.springframework.amqp.core.Message amqpReplyMessage = this.amqpTemplate.sendAndReceive(exchangeName, routingKey, amqpMessage);
|
||||
if (amqpReplyMessage == null) {
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.amqp.outbound;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import org.springframework.amqp.core.Message;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.rabbit.support.CorrelationData;
|
||||
import org.springframework.integration.MessageHeaders;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OutboundEndpointTests {
|
||||
|
||||
@Test
|
||||
public void testHeaderMapperWinsAdapter() {
|
||||
ConnectionFactory connectionFactory = mock(ConnectionFactory.class);
|
||||
RabbitTemplate amqpTemplate = spy(new RabbitTemplate(connectionFactory));
|
||||
AmqpOutboundEndpoint endpoint = new AmqpOutboundEndpoint(amqpTemplate);
|
||||
final AtomicReference<Message> amqpMessage =
|
||||
new AtomicReference<Message>();
|
||||
doAnswer(new Answer<Object>() {
|
||||
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
amqpMessage.set((Message) invocation.getArguments()[2]);
|
||||
return null;
|
||||
}
|
||||
}).when(amqpTemplate).send(anyString(), anyString(), any(Message.class),
|
||||
any(CorrelationData.class));
|
||||
org.springframework.integration.Message<?> message = MessageBuilder.withPayload("foo")
|
||||
.setHeader(MessageHeaders.CONTENT_TYPE, "bar")
|
||||
.build();
|
||||
endpoint.handleMessage(message);
|
||||
assertNotNull(amqpMessage.get());
|
||||
assertEquals("bar", amqpMessage.get().getMessageProperties().getContentType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderMapperWinsGateway() {
|
||||
ConnectionFactory connectionFactory = mock(ConnectionFactory.class);
|
||||
TestRabbitTemplate amqpTemplate = spy(new TestRabbitTemplate(connectionFactory));
|
||||
AmqpOutboundEndpoint endpoint = new AmqpOutboundEndpoint(amqpTemplate);
|
||||
endpoint.setExpectReply(true);
|
||||
final AtomicReference<Message> amqpMessage =
|
||||
new AtomicReference<Message>();
|
||||
doAnswer(new Answer<Object>() {
|
||||
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
amqpMessage.set((Message) invocation.getArguments()[2]);
|
||||
return null;
|
||||
}
|
||||
}).when(amqpTemplate).doSendAndReceiveWithTemporary(anyString(), anyString(), any(Message.class));
|
||||
org.springframework.integration.Message<?> message = MessageBuilder.withPayload("foo")
|
||||
.setHeader(MessageHeaders.CONTENT_TYPE, "bar")
|
||||
.build();
|
||||
endpoint.handleMessage(message);
|
||||
assertNotNull(amqpMessage.get());
|
||||
assertEquals("bar", amqpMessage.get().getMessageProperties().getContentType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase method visibility
|
||||
*/
|
||||
private class TestRabbitTemplate extends RabbitTemplate {
|
||||
|
||||
private TestRabbitTemplate(ConnectionFactory connectionFactory) {
|
||||
super(connectionFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.springframework.amqp.core.Message doSendAndReceiveWithTemporary(String exchange,
|
||||
String routingKey, org.springframework.amqp.core.Message message) {
|
||||
return super.doSendAndReceiveWithTemporary(exchange, routingKey, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -144,6 +144,24 @@
|
||||
before sending the request. For more information see <xref linkend="http"/>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="3.0-amqp-mapping">
|
||||
<title>AMQP Outbound Gateway Header Mapping</title>
|
||||
<para>
|
||||
Previously, the <int-amqp:outbound-gateway/> mapped headers before invoking the message
|
||||
converter, and the converter could overwrite headers such as <code>content-type</code>. The
|
||||
outbound adapter maps the headers after the conversion, which means headers like
|
||||
<code>content-type</code> from the outbound <code>Message</code> (if present) are used.
|
||||
</para>
|
||||
<para>
|
||||
Starting with this release, the gateway now maps the headers after the message conversion,
|
||||
consistent with the adapter. If your application relies on the previous behavior (where the
|
||||
converter's headers overrode the mapped headers), you either need to filter those headers
|
||||
(before the message reaches the gateway)
|
||||
or set them appropriately. The headers affected by the <classname>SimpleMessageConverter</classname>
|
||||
are <code>content-type</code> and <code>content-encoding</code>. Custom message converters
|
||||
may set other headers.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
Reference in New Issue
Block a user