title: Spring amqp reject message outside a listener
body: <p>The application uses java 10, spring amqp and rabbitmq.</p>
  
  <p>The system has a dead letter queue where we send some messages (they couldn't be processed as expected because of database unavailability).</p>
  
  <p>For now, database availability is checked every X seconds and, if available only, we re-queue messages to their original queue. Otherwise we do nothing and messages stays in the dead letter queue.</p>
  
  <p>When re-queued to original queue, messages can go back to dead letter queue again and see the x-death header count growing.</p>
  
  <p>For some reasons, we would like to process dead-lettered messages that have count >= 5 (for example) and re-queue others to the dead letter queue.</p>
  
  <p>I need to basic ack the message first to check the x-death count header, then send it to the original queue if count is big enough, else re-queue in dead letter queue.</p>
  
  <p>I can't manage to re-queue to dead letter queue because the basic get in not inside a listener: throwing AmqpRejectAndDontRequeueException doesn't work as the exception is not thrown inside a rabbitmq listener object.</p>
  
  <p>I tried throwing the exception inside a receiveAndCallback method, but this seems not better:</p>
  
  <pre><code>rabbitTemplate.receiveAndReply(queueName, new ReceiveAndReplyCallback&lt;Message, Object&gt;() {
  
          @Override
          public Object handle(Message message) {
              Long messageXdeathCount = null;
              if (null != message.getMessageProperties() &amp;&amp; null != message.getMessageProperties().getHeaders()) {
                  List&lt;Map&lt;String, ?&gt;&gt; xdeathHeader =
                          (List&lt;Map&lt;String, ?&gt;&gt;) message.getMessageProperties().getHeaders().get(
                          "x-death");
                  if (null != xdeathHeader &amp;&amp; null != xdeathHeader.get(0)) {
                      messageXdeathCount = (Long) xdeathHeader.get(0).get("count");
                  }
              }
              if (messageXdeathCount == null) {
                  messageXdeathCount = 0L;
              }
              if (messageXdeathCount &gt;= 5) {
                  resendsMessage(message);
              } else {
                  // this does not reject the message
                  throw new AmqpRejectAndDontRequeueException("rejected");
              }
              return null;
          }
      });
      return receive;
  }
  </code></pre>
  
  <p>After this method execution, the message is not rejected as I expect and is away from the queue (it has been acked).</p>
  
  <p>Here is the exchange and queue declaration:</p>
  
  <pre><code>@Bean
  public Exchange exchange() {
      TopicExchange exchange = new TopicExchange(EXCHANGE, true, false);
      admin().declareExchange(exchange);
      Map&lt;String, Object&gt; args = new HashMap&lt;String, Object&gt;();
      args.put("x-dead-letter-exchange", EXCHANGE);
      Queue queue = new Queue("queueName", true, false, false, args);
      admin().declareQueue(queue);
      Binding binding = BindingBuilder.bind(queue).to(exchange).with(routingKey).noargs();
      admin().declareBinding(binding);
      return exchange;
  }
  </code></pre>
  
  <p>How can reject the messages in the dead letter queue without using the AmqpRejectAndDontRequeueException?
  Is is possible for an exchange to have x-dead-letter-exchange set to self?</p>
  
  <p>Thanks for your help</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>I tried another way, with channel get and reject:</p>
  
  <pre><code>// exchange creation
  @Bean
  public Exchange exchange() throws IOException {
      Connection connection = connectionFactory().createConnection();
      Channel channel = channel();
      channel.exchangeDeclare(EXCHANGE, ExchangeTypes.TOPIC, true, false, null);
      Map&lt;String, Object&gt; args = new HashMap&lt;String, Object&gt;();
      args.put("x-dead-letter-exchange", EXCHANGE);
      channel.queueDeclare("queueName", true, false, false, args);
      channel.queueBind("queueName", EXCHANGE, routingKey);
      return exchange;
  }
  </code></pre>
  
  <p>Message get and ack or reject:</p>
  
  <pre><code>GetResponse response = channel.basicGet(queueName, false);
  Long messageXdeathCount = null;
  if(null != response.getProps() &amp;&amp; null != response.getProps().getHeaders()) {
      List&lt;Map&lt;String, ?&gt;&gt; xdeathHeader =
              (List&lt;Map&lt;String, ?&gt;&gt;) response.getProps().getHeaders().get("x-death");
      if(null != xdeathHeader &amp;&amp; null != xdeathHeader.get(0)) {
          messageXdeathCount = (Long) xdeathHeader.get(0).get("count");
      }
  }
  if (messageXdeathCount == null) {
      messageXdeathCount = 0L;
  }
  if (messageXdeathCount &gt;= 5) {
      MessagePropertiesConverter messagePropertiesConverter = new DefaultMessagePropertiesConverter();
      MessageProperties messageProps =
              messagePropertiesConverter.toMessageProperties(response.getProps(),
  response.getEnvelope(), "UTF-8");
      resendsMessage(new Message(response.getBody(), messageProps));
      channel.basicAck(response.getEnvelope().getDeliveryTag(), false);
  } else {
      if(response.getProps().getHeaders().get("x-death") == null) {
          response.getProps().getHeaders().put("x-death", new ArrayList&lt;&gt;());
      }
      if(((List&lt;Map&lt;String, Object&gt;&gt;) response.getProps().getHeaders().get("x-death")).get(0) == null) {
          ((List&lt;Map&lt;String, Object&gt;&gt;)response.getProps().getHeaders().get("x-death")).add(new HashMap&lt;&gt;());
      }
      ((List&lt;Map&lt;String, Object&gt;&gt;) response.getProps().getHeaders().get("x-death")).get(0).put(
              "count", messageXdeathCount + 1);
      channel.basicReject(response.getEnvelope().getDeliveryTag(), true);
  }
  </code></pre>
  
  <p>First I realized that it was quite ugly, then that messages cannot be updated between get and rejected. It there a way to use channel.basicReject and update the x-death count header?</p>