2
votes

I'm trying to use org.springframework.cloud.aws.messaging.core.NotificationMessagingTemplate (from Spring Cloud AWS) to post notifications to a SNS Topic.

Every time a notification is posted a warning message is generated:

WARN [org.springframework.cloud.aws.messaging.core.TopicMessageChannel] Message header with name 'id' and type 'java.util.UUID' cannot be sent as message attribute because it is not supported by SNS.

The issue seems to be that org.springframework.messaging.MessageHeaders generates automagically an id header, of type java.util.UUID, which is not something that spring cloud knows how to handle.

Is there a way to avoid that automatic header generation (I can live without an UUID here) or avoid the warning, besides just suppressing the log?

Something similar is also affecting SQS:

Related Question: spring-cloud-aws Spring creates message header attribute not supported by SQS Related Bug: Warning "'java.util.UUID' cannot be sent as message attribute ..." on any request sent to SQS channel

My Controller looks something like this:

package com.stackoverflow.sample.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.aws.messaging.core.NotificationMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/whatever")
public class SampleController {

    @Autowired
    private NotificationMessagingTemplate template;

    @RequestMapping(method = RequestMethod.GET)
        public String handleGet() {
            this.template.sendNotification("message", "subject");
            return "yay";
        }
    }
}

My Spring configuration looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:aws-context="http://www.springframework.org/schema/cloud/aws/context"
        xmlns:aws-messaging="http://www.springframework.org/schema/cloud/aws/messaging"
    xsi:schemaLocation="
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
        http://www.springframework.org/schema/cloud/aws/context http://www.springframework.org/schema/cloud/spring-cloud-aws-context.xsd
        http://www.springframework.org/schema/cloud/aws/messaging http://www.springframework.org/schema/cloud/spring-cloud-aws-messaging.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.stackoverflow.sample" />
    <mvc:annotation-driven />

    <aws-context:context-credentials>
        <aws-context:instance-profile-credentials/>
        <aws-context:simple-credentials access-key="MyKey" secret-key="mySecret" />
    </aws-context:context-credentials>

    <aws-messaging:notification-messaging-template id="notificationMessagingTemplate" region="us-west-2" default-destination="myTopic" />
</beans>
1

1 Answers

4
votes

The problem occurs because the constructor called MessageHeaders class

MessageHeaders class

MessageHeaders(Map<String, Object> headers) { } on line 39

And to not send the id header you need to call the constructor MessageHeaders class

MessageHeaders(Map<String, Object> headers, UUID id, Long timestamp){} on line 43

because this constructor has the condition does not create the id header automatically

to stop sending the header id you need to override the MessageHeader and NotificationMessagingTemplate classes

class MessageHeaders

public class MessageHeadersCustom extends MessageHeaders {
    public MessageHeadersCustom() {
        super(new HashMap<String, Object>(), ID_VALUE_NONE, null);
    }
}

class NotificationMessagingTemplate

public class NotificationMessagingTemplateCustom extends NotificationMessagingTemplate {

    public NotificationMessagingTemplateCustom(AmazonSNS amazonSns) {
        super(amazonSns);
    }

    @Override
    public void sendNotification(Object message, String subject) {

        MessageHeaders headersCustom = new MessageHeadersCustom();
        headersCustom.put(TopicMessageChannel.NOTIFICATION_SUBJECT_HEADER, subject);

        this.convertAndSend(getRequiredDefaultDestination(), message, headersCustom);
    }
}

And finally, your class that will make the call need to use your implementation

package com.stackoverflow.sample.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.aws.messaging.core.NotificationMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/whatever")
public class SampleController {

    @Autowired
    private NotificationMessagingTemplateCustom template;

    @RequestMapping(method = RequestMethod.GET)
        public String handleGet() {
            this.template.sendNotification("message", "subject");
            return "yay";
        }
    }
}