spring-cloud-aws
spring-cloud-aws copied to clipboard
Handling of SNS MessageAttributes in NotificationRequestConverter seems incorrect
Describe the bug Spring Cloud AWS Messaging 2.1.4.RELEASE
Sample I was looking at NotificationRequestConverter#getMessageAttributesAsMessageHeaders and noticed a couple of issues.
- Binary type is actually wrapping the output of Type, not Value. It also doesn't decode the string.
- String.Array isn't supported.
I ended up updating my own for a similar purpose, and came up with:
private static Map<String, Object> getMessageAttributesAsMessageHeaders(final JsonNode message) {
final Map<String, Object> messageHeaders = new HashMap<>();
final Iterator<String> fieldNames = message.fieldNames();
while (fieldNames.hasNext()) {
String attributeName = fieldNames.next();
String attributeValue = message.get(attributeName).get("Value").asText();
String attributeType = message.get(attributeName).get("Type").asText();
if (MessageHeaders.CONTENT_TYPE.equals(attributeName)) {
messageHeaders.put(MessageHeaders.CONTENT_TYPE, MimeType.valueOf(attributeValue));
} else if (MessageHeaders.ID.equals(attributeName)) {
messageHeaders.put(MessageHeaders.ID, UUID.fromString(attributeValue));
} else {
if (MessageAttributeDataTypes.STRING.equals(attributeType)) {
messageHeaders.put(attributeName, attributeValue);
} else if ("String.Array".equalsIgnoreCase(attributeType)) {
final List<?> arrayValue = getArrayValue(attributeType, attributeValue);
if (arrayValue != null) {
messageHeaders.put(attributeName, arrayValue);
}
} else if (attributeType.startsWith(MessageAttributeDataTypes.NUMBER)) {
Object numberValue = getNumberValue(attributeType, attributeValue);
messageHeaders.put(attributeName, numberValue);
} else if (MessageAttributeDataTypes.BINARY.equals(attributeType)) {
messageHeaders.put(attributeName, ByteBuffer.wrap(Base64.decode(attributeValue)));
}
}
}
return messageHeaders;
}
private static Object getNumberValue(String attributeType, String attributeValue) {
final String numberType = attributeType.substring(MessageAttributeDataTypes.NUMBER.length() + 1);
try {
final Class<? extends Number> numberTypeClass = Class.forName(numberType).asSubclass(Number.class);
return NumberUtils.parseNumber(attributeValue, numberTypeClass);
} catch (ClassNotFoundException e) {
throw new MessagingException(String.format(
"Message attribute with value '%s' and data type '%s' could not be converted "
+ "into a Number because target class was not found.",
attributeValue, attributeType), e);
}
}
private static List<?> getArrayValue(String attributeType, String attributeValue) {
try {
return objectMapper.readValue(attributeValue, List.class);
} catch (IOException e) {
throw new MessagingException(String.format(
"Message attribute with value '%s' and data type '%s' could not be converted into an Array.",
attributeValue, attributeType), e);
}
}
This handling of the Binary and String.Array types functions the way I was expecting in my tests.
Doesn't look like anyone else come across this though, so just flagging it as a possible issue at the moment