Skip to content

Commit 2a2a497

Browse files
author
bwynn
committed
Support SQS attribute data type 'Number' per:
https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-attributes.html Double isn't large enough to hold a SQS 'Number' so we need to leave it as a string, and potentially interpret on the outgoing side.
1 parent ec0677b commit 2a2a497

File tree

3 files changed

+108
-65
lines changed

3 files changed

+108
-65
lines changed

src/main/java/com/amazon/sqs/javamessaging/SQSMessagingClientConstants.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ public class SQSMessagingClientConstants {
3030

3131
public static final int MIN_PREFETCH = 0;
3232

33+
/**
34+
* SQS Message Attribute data type.
35+
* https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-attributes.html
36+
*/
37+
public static final String NUMBER = "Number";
38+
3339
/**
3440
* JMSMessage available user property types, which are mapped to message
3541
* attribute data types

src/main/java/com/amazon/sqs/javamessaging/message/SQSMessage.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,7 @@ private void mapSystemAttributeToJmsMessageProperty(Map<String,String> systemAtt
159159

160160
private void addMessageAttributes(com.amazonaws.services.sqs.model.Message sqsMessage) throws JMSException {
161161
for (Entry<String, MessageAttributeValue> entry : sqsMessage.getMessageAttributes().entrySet()) {
162-
properties.put(entry.getKey(), new JMSMessagePropertyValue(
163-
entry.getValue().getStringValue(), entry.getValue().getDataType()));
162+
properties.put(entry.getKey(), new JMSMessagePropertyValue(entry.getValue().getStringValue(), entry.getValue().getDataType()));
164163
}
165164
}
166165

@@ -1210,6 +1209,9 @@ private static Object getObjectValue(String value, String type) throws JMSExcept
12101209
return Float.valueOf(value);
12111210
} else if (SHORT.equals(type)) {
12121211
return Short.valueOf(value);
1212+
} else if (NUMBER.equals(type)) {
1213+
// This may not be a JMS Type but it is a SQS Type, so we had better support it.
1214+
return value;
12131215
} else {
12141216
throw new JMSException(type + " is not a supported JMS property type");
12151217
}

src/test/java/com/amazon/sqs/javamessaging/message/SQSMessageTest.java

Lines changed: 98 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,24 @@
2828
import com.amazon.sqs.javamessaging.acknowledge.Acknowledger;
2929
import com.amazon.sqs.javamessaging.message.SQSMessage;
3030
import com.amazonaws.services.sqs.model.MessageAttributeValue;
31+
32+
import org.junit.Assert;
3133
import org.junit.Before;
3234
import org.junit.Test;
3335

3436
import javax.jms.Message;
3537
import javax.jms.MessageFormatException;
3638
import javax.jms.MessageNotWriteableException;
3739

38-
import junit.framework.Assert;
39-
4040
import java.util.*;
4141

4242
/**
4343
* Test the SQSMessageTest class
4444
*/
4545
public class SQSMessageTest {
4646
private SQSSession mockSQSSession;
47+
final String myNumber = "myNumber";
48+
final String myNumberOverflow = "myNumberOverflow";
4749
final String myTrueBoolean = "myTrueBoolean";
4850
final String myFalseBoolean = "myFalseBoolean";
4951
final String myInteger = "myInteger";
@@ -67,65 +69,66 @@ public void testProperty() throws JMSException {
6769
when(mockSQSSession.createMessage()).thenReturn(new SQSMessage());
6870
Message message = mockSQSSession.createMessage();
6971

70-
message.setBooleanProperty("myTrueBoolean", true);
71-
message.setBooleanProperty("myFalseBoolean", false);
72-
message.setIntProperty("myInteger", 100);
73-
message.setDoubleProperty("myDouble", 2.1768);
74-
message.setFloatProperty("myFloat", 3.1457f);
75-
message.setLongProperty("myLong", 1290772974281L);
76-
message.setShortProperty("myShort", (short) 123);
77-
message.setByteProperty("myByteProperty", (byte) 'a');
78-
message.setStringProperty("myString", "StringValue");
79-
80-
Assert.assertTrue(message.propertyExists("myTrueBoolean"));
81-
Assert.assertEquals(message.getObjectProperty("myTrueBoolean"), true);
82-
Assert.assertEquals(message.getBooleanProperty("myTrueBoolean"), true);
72+
message.setBooleanProperty(myTrueBoolean, true);
73+
message.setBooleanProperty(myFalseBoolean, false);
74+
message.setIntProperty(myInteger, 100);
75+
message.setDoubleProperty(myDouble, 2.1768);
76+
message.setFloatProperty(myFloat, 3.1457f);
77+
message.setLongProperty(myLong, 1290772974281L);
78+
message.setShortProperty(myShort, (short) 123);
79+
message.setByteProperty(myByte, (byte) 'a');
80+
message.setStringProperty(myString, "StringValue");
81+
82+
Assert.assertTrue(message.propertyExists(myTrueBoolean));
83+
Assert.assertEquals(message.getObjectProperty(myTrueBoolean), true);
84+
Assert.assertEquals(message.getBooleanProperty(myTrueBoolean), true);
8385

84-
Assert.assertTrue(message.propertyExists("myFalseBoolean"));
85-
Assert.assertEquals(message.getObjectProperty("myFalseBoolean"), false);
86-
Assert.assertEquals(message.getBooleanProperty("myFalseBoolean"), false);
86+
Assert.assertTrue(message.propertyExists(myFalseBoolean));
87+
Assert.assertEquals(message.getObjectProperty(myFalseBoolean), false);
88+
Assert.assertEquals(message.getBooleanProperty(myFalseBoolean), false);
8789

88-
Assert.assertTrue(message.propertyExists("myInteger"));
89-
Assert.assertEquals(message.getObjectProperty("myInteger"), 100);
90-
Assert.assertEquals(message.getIntProperty("myInteger"), 100);
90+
Assert.assertTrue(message.propertyExists(myInteger));
91+
Assert.assertEquals(message.getObjectProperty(myInteger), 100);
92+
Assert.assertEquals(message.getIntProperty(myInteger), 100);
9193

92-
Assert.assertTrue(message.propertyExists("myDouble"));
93-
Assert.assertEquals(message.getObjectProperty("myDouble"), 2.1768);
94-
Assert.assertEquals(message.getDoubleProperty("myDouble"), 2.1768);
94+
Assert.assertTrue(message.propertyExists(myDouble));
95+
Assert.assertEquals((double)message.getObjectProperty(myDouble), 2.1768, 0);
96+
Assert.assertEquals(message.getDoubleProperty(myDouble), 2.1768, 0);
9597

96-
Assert.assertTrue(message.propertyExists("myFloat"));
97-
Assert.assertEquals(message.getObjectProperty("myFloat"), 3.1457f);
98-
Assert.assertEquals(message.getFloatProperty("myFloat"), 3.1457f);
98+
Assert.assertTrue(message.propertyExists(myFloat));
99+
Assert.assertEquals((float)message.getObjectProperty(myFloat), 3.1457f, 0);
100+
Assert.assertEquals(message.getFloatProperty(myFloat), 3.1457f, 0);
99101

100-
Assert.assertTrue(message.propertyExists("myLong"));
101-
Assert.assertEquals(message.getObjectProperty("myLong"), 1290772974281L);
102-
Assert.assertEquals(message.getLongProperty("myLong"), 1290772974281L);
102+
Assert.assertTrue(message.propertyExists(myLong));
103+
Assert.assertEquals(message.getObjectProperty(myLong), 1290772974281L);
104+
Assert.assertEquals(message.getLongProperty(myLong), 1290772974281L);
103105

104-
Assert.assertTrue(message.propertyExists("myShort"));
105-
Assert.assertEquals(message.getObjectProperty("myShort"), (short) 123);
106-
Assert.assertEquals(message.getShortProperty("myShort"), (short) 123);
106+
Assert.assertTrue(message.propertyExists(myShort));
107+
Assert.assertEquals(message.getObjectProperty(myShort), (short) 123);
108+
Assert.assertEquals(message.getShortProperty(myShort), (short) 123);
107109

108-
Assert.assertTrue(message.propertyExists("myByteProperty"));
109-
Assert.assertEquals(message.getObjectProperty("myByteProperty"), (byte) 'a');
110-
Assert.assertEquals(message.getByteProperty("myByteProperty"), (byte) 'a');
110+
Assert.assertTrue(message.propertyExists(myByte));
111+
Assert.assertEquals(message.getObjectProperty(myByte), (byte) 'a');
112+
Assert.assertEquals(message.getByteProperty(myByte), (byte) 'a');
111113

112-
Assert.assertTrue(message.propertyExists("myString"));
113-
Assert.assertEquals(message.getObjectProperty("myString"), "StringValue");
114-
Assert.assertEquals(message.getStringProperty("myString"), "StringValue");
114+
Assert.assertTrue(message.propertyExists(myString));
115+
Assert.assertEquals(message.getObjectProperty(myString), "StringValue");
116+
Assert.assertEquals(message.getStringProperty(myString), "StringValue");
115117

116118
// Validate property names
117119
Set<String> propertyNamesSet = new HashSet<String>(Arrays.asList(
118-
"myTrueBoolean",
119-
"myFalseBoolean",
120-
"myInteger",
121-
"myDouble",
122-
"myFloat",
123-
"myLong",
124-
"myShort",
125-
"myByteProperty",
126-
"myString"));
120+
myTrueBoolean,
121+
myFalseBoolean,
122+
myInteger,
123+
myDouble,
124+
myFloat,
125+
myLong,
126+
myShort,
127+
myByte,
128+
myString));
127129

128-
Enumeration<String > propertyNames = message.getPropertyNames();
130+
@SuppressWarnings("unchecked")
131+
Enumeration<String> propertyNames = message.getPropertyNames();
129132
int counter = 0;
130133
while (propertyNames.hasMoreElements()) {
131134
assertTrue(propertyNamesSet.contains(propertyNames.nextElement()));
@@ -134,15 +137,10 @@ public void testProperty() throws JMSException {
134137
assertEquals(propertyNamesSet.size(), counter);
135138

136139
message.clearProperties();
137-
Assert.assertFalse(message.propertyExists("myTrueBoolean"));
138-
Assert.assertFalse(message.propertyExists("myInteger"));
139-
Assert.assertFalse(message.propertyExists("myDouble"));
140-
Assert.assertFalse(message.propertyExists("myFloat"));
141-
Assert.assertFalse(message.propertyExists("myLong"));
142-
Assert.assertFalse(message.propertyExists("myShort"));
143-
Assert.assertFalse(message.propertyExists("myByteProperty"));
144-
Assert.assertFalse(message.propertyExists("myString"));
145-
140+
for (String propName: propertyNamesSet) {
141+
Assert.assertFalse(message.propertyExists(propName));
142+
}
143+
146144
propertyNames = message.getPropertyNames();
147145
assertFalse(propertyNames.hasMoreElements());
148146
}
@@ -272,11 +270,23 @@ public void testSQSMessageAttributeToProperty() throws JMSException {
272270

273271
Acknowledger ack = mock(Acknowledger.class);
274272

273+
// 52 digits of value.
274+
final String numberOverflowValue = "1234567890123456789012345678901234567890123456789012";
275+
275276
Map<String,String> systemAttributes = new HashMap<String, String>();
276277
systemAttributes.put(APPROXIMATE_RECEIVE_COUNT, "100");
277278

278279
Map<String, MessageAttributeValue> messageAttributes = new HashMap<String, MessageAttributeValue>();
279280

281+
/* SQS Supports Logical Data Types: String, Number, and Binary so we'd best know what to do with those at the very minimum! */
282+
messageAttributes.put(myNumber, new MessageAttributeValue()
283+
.withDataType(SQSMessagingClientConstants.NUMBER)
284+
.withStringValue("4"));
285+
286+
messageAttributes.put(myNumberOverflow, new MessageAttributeValue()
287+
.withDataType(SQSMessagingClientConstants.NUMBER)
288+
.withStringValue(numberOverflowValue));
289+
280290
messageAttributes.put(myTrueBoolean, new MessageAttributeValue()
281291
.withDataType(SQSMessagingClientConstants.BOOLEAN)
282292
.withStringValue("1"));
@@ -312,6 +322,7 @@ public void testSQSMessageAttributeToProperty() throws JMSException {
312322
messageAttributes.put(myString, new MessageAttributeValue()
313323
.withDataType(SQSMessagingClientConstants.STRING)
314324
.withStringValue("StringValue"));
325+
315326

316327
com.amazonaws.services.sqs.model.Message sqsMessage = new com.amazonaws.services.sqs.model.Message()
317328
.withMessageAttributes(messageAttributes)
@@ -321,6 +332,27 @@ public void testSQSMessageAttributeToProperty() throws JMSException {
321332

322333
SQSMessage message = new SQSMessage(ack, "QueueUrl", sqsMessage);
323334

335+
// SQS "Number" data type must use StringValue, may be a floating point number
336+
Assert.assertTrue(message.propertyExists(myNumber));
337+
Assert.assertEquals("4", message.getObjectProperty(myNumber));
338+
Assert.assertEquals("4", message.getStringProperty(myNumber));
339+
Assert.assertEquals(4, message.getIntProperty(myNumber));
340+
Assert.assertEquals(4.0, message.getDoubleProperty(myNumber), 0);
341+
342+
// A Number can hold a value with quite a lot of significant digits, it must be represented as a StringValue,
343+
// and can be interpreted as other things, but we should expect errors if the value overflows.
344+
Assert.assertTrue(message.propertyExists(myNumberOverflow));
345+
Assert.assertEquals(numberOverflowValue, message.getObjectProperty(myNumberOverflow));
346+
Assert.assertEquals(numberOverflowValue, message.getStringProperty(myNumberOverflow));
347+
// Expecting a loss of precision here when interpreted as a double.
348+
Assert.assertEquals(1.23456789012345678E51, message.getDoubleProperty(myNumberOverflow), 0);
349+
try {
350+
message.getIntProperty(myNumberOverflow);
351+
Assert.fail("message.getIntProperty did not throw a NumberFormatException");
352+
} catch (NumberFormatException nfe) {
353+
Assert.assertEquals("For input string: \""+numberOverflowValue+"\"", nfe.getMessage());
354+
}
355+
324356
Assert.assertTrue(message.propertyExists(myTrueBoolean));
325357
Assert.assertEquals(message.getObjectProperty(myTrueBoolean), true);
326358
Assert.assertEquals(message.getBooleanProperty(myTrueBoolean), true);
@@ -334,12 +366,12 @@ public void testSQSMessageAttributeToProperty() throws JMSException {
334366
Assert.assertEquals(message.getIntProperty(myInteger), 100);
335367

336368
Assert.assertTrue(message.propertyExists(myDouble));
337-
Assert.assertEquals(message.getObjectProperty(myDouble), 2.1768);
338-
Assert.assertEquals(message.getDoubleProperty(myDouble), 2.1768);
369+
Assert.assertEquals((double)message.getObjectProperty(myDouble), 2.1768, 0);
370+
Assert.assertEquals(message.getDoubleProperty(myDouble), 2.1768, 0);
339371

340372
Assert.assertTrue(message.propertyExists(myFloat));
341-
Assert.assertEquals(message.getObjectProperty(myFloat), 3.1457f);
342-
Assert.assertEquals(message.getFloatProperty(myFloat), 3.1457f);
373+
Assert.assertEquals((float)message.getObjectProperty(myFloat), 3.1457f, 0);
374+
Assert.assertEquals(message.getFloatProperty(myFloat), 3.1457f, 0);
343375

344376
Assert.assertTrue(message.propertyExists(myLong));
345377
Assert.assertEquals(message.getObjectProperty(myLong), 1290772974281L);
@@ -360,6 +392,8 @@ public void testSQSMessageAttributeToProperty() throws JMSException {
360392

361393
// Validate property names
362394
Set<String> propertyNamesSet = new HashSet<String>(Arrays.asList(
395+
myNumber,
396+
myNumberOverflow,
363397
myTrueBoolean,
364398
myFalseBoolean,
365399
myInteger,
@@ -374,7 +408,8 @@ public void testSQSMessageAttributeToProperty() throws JMSException {
374408
Enumeration<String > propertyNames = message.getPropertyNames();
375409
int counter = 0;
376410
while (propertyNames.hasMoreElements()) {
377-
assertTrue(propertyNamesSet.contains(propertyNames.nextElement()));
411+
String propName = propertyNames.nextElement();
412+
Assert.assertTrue("Found Unknown Property: " + propName, propertyNamesSet.contains(propName));
378413
counter++;
379414
}
380415
assertEquals(propertyNamesSet.size(), counter);

0 commit comments

Comments
 (0)