@Test
  public void testReplyToOneDeepCustomCorrelationKey() throws Exception {
    ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class);
    Connection mockConnection = mock(Connection.class);
    Channel mockChannel = mock(Channel.class);

    when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection);
    when(mockConnection.isOpen()).thenReturn(true);
    when(mockConnection.createChannel()).thenReturn(mockChannel);

    final RabbitTemplate template =
        new RabbitTemplate(new SingleConnectionFactory(mockConnectionFactory));
    template.setCorrelationKey(CORRELATION_HEADER);
    Queue replyQueue = new Queue("new.replyTo");
    template.setReplyQueue(replyQueue);

    MessageProperties messageProperties = new MessageProperties();
    messageProperties.setReplyTo("replyTo1");
    messageProperties.setCorrelationId("saveThis".getBytes());
    Message message = new Message("Hello, world!".getBytes(), messageProperties);
    final AtomicReference<String> replyTo = new AtomicReference<String>();
    final AtomicReference<String> correlationId = new AtomicReference<String>();
    doAnswer(
            new Answer<Object>() {
              public Object answer(InvocationOnMock invocation) throws Throwable {
                BasicProperties basicProps = (BasicProperties) invocation.getArguments()[4];
                replyTo.set(basicProps.getReplyTo());
                correlationId.set((String) basicProps.getHeaders().get(CORRELATION_HEADER));

                MessageProperties springProps =
                    new DefaultMessagePropertiesConverter()
                        .toMessageProperties(basicProps, null, "UTF-8");
                Message replyMessage = new Message("!dlrow olleH".getBytes(), springProps);
                template.onMessage(replyMessage);
                return null;
              }
            })
        .when(mockChannel)
        .basicPublish(
            Mockito.any(String.class),
            Mockito.any(String.class),
            Mockito.anyBoolean(),
            Mockito.anyBoolean(),
            Mockito.any(BasicProperties.class),
            Mockito.any(byte[].class));
    Message reply = template.sendAndReceive(message);
    assertNotNull(reply);

    assertNotNull(replyTo.get());
    assertEquals("new.replyTo", replyTo.get());
    assertNotNull(correlationId.get());
    assertEquals("replyTo1", reply.getMessageProperties().getReplyTo());
    assertTrue(!"saveThis".equals(correlationId.get()));
    assertEquals("replyTo1", reply.getMessageProperties().getReplyTo());
  }
 public MessageProperties toMessageProperties(
     final BasicProperties source, final Envelope envelope, final String charset) {
   MessageProperties target = new MessageProperties();
   Map<String, Object> headers = source.getHeaders();
   if (!CollectionUtils.isEmpty(headers)) {
     for (Map.Entry<String, Object> entry : headers.entrySet()) {
       String key = entry.getKey();
       if (MessageProperties.X_DELAY.equals(key)) {
         Object value = entry.getValue();
         if (value instanceof Integer) {
           target.setReceivedDelay((Integer) value);
         }
       } else {
         target.setHeader(key, convertLongStringIfNecessary(entry.getValue(), charset));
       }
     }
   }
   target.setTimestamp(source.getTimestamp());
   target.setMessageId(source.getMessageId());
   target.setReceivedUserId(source.getUserId());
   target.setAppId(source.getAppId());
   target.setClusterId(source.getClusterId());
   target.setType(source.getType());
   Integer deliveryMode = source.getDeliveryMode();
   if (deliveryMode != null) {
     target.setReceivedDeliveryMode(MessageDeliveryMode.fromInt(deliveryMode));
   }
   target.setDeliveryMode(null);
   target.setExpiration(source.getExpiration());
   target.setPriority(source.getPriority());
   target.setContentType(source.getContentType());
   target.setContentEncoding(source.getContentEncoding());
   String correlationId = source.getCorrelationId();
   if (StringUtils.hasText(correlationId)) {
     target.setCorrelationId(source.getCorrelationId());
   }
   String replyTo = source.getReplyTo();
   if (replyTo != null) {
     target.setReplyTo(replyTo);
   }
   if (envelope != null) {
     target.setReceivedExchange(envelope.getExchange());
     target.setReceivedRoutingKey(envelope.getRoutingKey());
     target.setRedelivered(envelope.isRedeliver());
     target.setDeliveryTag(envelope.getDeliveryTag());
   }
   return target;
 }
  /**
   * Maps headers from a Spring Integration MessageHeaders instance to the MessageProperties of an
   * AMQP Message.
   */
  @Override
  protected void populateStandardHeaders(
      Map<String, Object> headers, MessageProperties amqpMessageProperties) {
    String appId = getHeaderIfAvailable(headers, AmqpHeaders.APP_ID, String.class);
    if (StringUtils.hasText(appId)) {
      amqpMessageProperties.setAppId(appId);
    }
    String clusterId = getHeaderIfAvailable(headers, AmqpHeaders.CLUSTER_ID, String.class);
    if (StringUtils.hasText(clusterId)) {
      amqpMessageProperties.setClusterId(clusterId);
    }
    String contentEncoding =
        getHeaderIfAvailable(headers, AmqpHeaders.CONTENT_ENCODING, String.class);
    if (StringUtils.hasText(contentEncoding)) {
      amqpMessageProperties.setContentEncoding(contentEncoding);
    }
    Long contentLength = getHeaderIfAvailable(headers, AmqpHeaders.CONTENT_LENGTH, Long.class);
    if (contentLength != null) {
      amqpMessageProperties.setContentLength(contentLength);
    }
    String contentType = this.extractContentTypeAsString(headers);

    if (StringUtils.hasText(contentType)) {
      amqpMessageProperties.setContentType(contentType);
    }
    Object correlationId = headers.get(AmqpHeaders.CORRELATION_ID);
    if (correlationId instanceof byte[]) {
      amqpMessageProperties.setCorrelationId((byte[]) correlationId);
    }
    MessageDeliveryMode deliveryMode =
        getHeaderIfAvailable(headers, AmqpHeaders.DELIVERY_MODE, MessageDeliveryMode.class);
    if (deliveryMode != null) {
      amqpMessageProperties.setDeliveryMode(deliveryMode);
    }
    Long deliveryTag = getHeaderIfAvailable(headers, AmqpHeaders.DELIVERY_TAG, Long.class);
    if (deliveryTag != null) {
      amqpMessageProperties.setDeliveryTag(deliveryTag);
    }
    String expiration = getHeaderIfAvailable(headers, AmqpHeaders.EXPIRATION, String.class);
    if (StringUtils.hasText(expiration)) {
      amqpMessageProperties.setExpiration(expiration);
    }
    Integer messageCount = getHeaderIfAvailable(headers, AmqpHeaders.MESSAGE_COUNT, Integer.class);
    if (messageCount != null) {
      amqpMessageProperties.setMessageCount(messageCount);
    }
    String messageId = getHeaderIfAvailable(headers, AmqpHeaders.MESSAGE_ID, String.class);
    if (StringUtils.hasText(messageId)) {
      amqpMessageProperties.setMessageId(messageId);
    }
    Integer priority = getHeaderIfAvailable(headers, MessageHeaders.PRIORITY, Integer.class);
    if (priority != null) {
      amqpMessageProperties.setPriority(priority);
    }
    String receivedExchange =
        getHeaderIfAvailable(headers, AmqpHeaders.RECEIVED_EXCHANGE, String.class);
    if (StringUtils.hasText(receivedExchange)) {
      amqpMessageProperties.setReceivedExchange(receivedExchange);
    }
    String receivedRoutingKey =
        getHeaderIfAvailable(headers, AmqpHeaders.RECEIVED_ROUTING_KEY, String.class);
    if (StringUtils.hasText(receivedRoutingKey)) {
      amqpMessageProperties.setReceivedRoutingKey(receivedRoutingKey);
    }
    Boolean redelivered = getHeaderIfAvailable(headers, AmqpHeaders.REDELIVERED, Boolean.class);
    if (redelivered != null) {
      amqpMessageProperties.setRedelivered(redelivered);
    }
    String replyTo = getHeaderIfAvailable(headers, AmqpHeaders.REPLY_TO, String.class);
    if (replyTo != null) {
      amqpMessageProperties.setReplyTo(replyTo);
    }
    Date timestamp = getHeaderIfAvailable(headers, AmqpHeaders.TIMESTAMP, Date.class);
    if (timestamp != null) {
      amqpMessageProperties.setTimestamp(timestamp);
    }
    String type = getHeaderIfAvailable(headers, AmqpHeaders.TYPE, String.class);
    if (type != null) {
      amqpMessageProperties.setType(type);
    }
    String userId = getHeaderIfAvailable(headers, AmqpHeaders.USER_ID, String.class);
    if (StringUtils.hasText(userId)) {
      amqpMessageProperties.setUserId(userId);
    }
    String replyCorrelation =
        getHeaderIfAvailable(headers, AmqpHeaders.SPRING_REPLY_CORRELATION, String.class);
    if (StringUtils.hasLength(replyCorrelation)) {
      amqpMessageProperties.setHeader("spring_reply_correlation", replyCorrelation);
    }
    String replyToStack =
        getHeaderIfAvailable(headers, AmqpHeaders.SPRING_REPLY_TO_STACK, String.class);
    if (StringUtils.hasLength(replyToStack)) {
      amqpMessageProperties.setHeader("spring_reply_to", replyToStack);
    }
  }
  @Test
  public void testReplyToThreeDeepCustomCorrelationKey() throws Exception {
    ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class);
    Connection mockConnection = mock(Connection.class);
    Channel mockChannel = mock(Channel.class);

    when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection);
    when(mockConnection.isOpen()).thenReturn(true);
    when(mockConnection.createChannel()).thenReturn(mockChannel);

    final RabbitTemplate template =
        new RabbitTemplate(new SingleConnectionFactory(mockConnectionFactory));
    template.setCorrelationKey(CORRELATION_HEADER);
    Queue replyQueue = new Queue("replyTo2");
    template.setReplyQueue(replyQueue);

    MessageProperties messageProperties = new MessageProperties();
    messageProperties.setReplyTo("replyTo1");
    messageProperties.setCorrelationId("a".getBytes());
    Message message = new Message("Hello, world!".getBytes(), messageProperties);
    final AtomicInteger count = new AtomicInteger();
    final List<String> nestedReplyTo = new ArrayList<String>();
    final List<String> nestedCorrelation = new ArrayList<String>();
    doAnswer(
            new Answer<Object>() {
              public Object answer(InvocationOnMock invocation) throws Throwable {
                BasicProperties basicProps = (BasicProperties) invocation.getArguments()[4];
                nestedReplyTo.add(basicProps.getReplyTo());
                nestedCorrelation.add(basicProps.getCorrelationId());
                MessageProperties springProps =
                    new DefaultMessagePropertiesConverter()
                        .toMessageProperties(basicProps, null, "UTF-8");
                Message replyMessage = new Message("!dlrow olleH".getBytes(), springProps);
                if (count.incrementAndGet() < 2) {
                  Message anotherMessage = new Message("Second".getBytes(), springProps);
                  template.setReplyQueue(new Queue("replyTo3"));
                  replyMessage = template.sendAndReceive(anotherMessage);
                  nestedReplyTo.add(replyMessage.getMessageProperties().getReplyTo());
                  nestedCorrelation.add(
                      (String)
                          replyMessage.getMessageProperties().getHeaders().get(CORRELATION_HEADER));
                }
                template.onMessage(replyMessage);
                return null;
              }
            })
        .when(mockChannel)
        .basicPublish(
            Mockito.any(String.class),
            Mockito.any(String.class),
            Mockito.anyBoolean(),
            Mockito.anyBoolean(),
            Mockito.any(BasicProperties.class),
            Mockito.any(byte[].class));
    Message reply = template.sendAndReceive(message);
    assertNotNull(reply);

    assertEquals(3, nestedReplyTo.size());
    assertEquals("replyTo2", nestedReplyTo.get(0));
    assertEquals("replyTo3", nestedReplyTo.get(1));
    assertEquals("replyTo2", nestedReplyTo.get(2)); // intermediate reply

    assertEquals("replyTo1", reply.getMessageProperties().getReplyTo());
    assertEquals("a", new String(reply.getMessageProperties().getCorrelationId(), "UTF-8"));
  }