'SqsListener String index out of bounds issue

I'm encountering a really weird problem when trying to use the @SQSListener annotation from the Spring Cloud module. Here's my listener method:

@SqsListener(value = "myproject-dev-au-error-queue")
public void listenPhoenix(String message) throws IOException {

    logger.info(message);
 }

However, once I run the project, it starts reading messages from the queue and fails with the following error:

Exception in thread "simpleMessageListenerContainer-4" Exception in thread "simpleMessageListenerContainer-6" Exception in thread "simpleMessageListenerContainer-9" Exception in thread "simpleMessageListenerContainer-10" java.lang.StringIndexOutOfBoundsException: String index out of range: -1
    at java.lang.String.substring(String.java:1931)
    at org.springframework.cloud.aws.messaging.core.QueueMessageUtils.getNumberValue(QueueMessageUtils.java:93)
    at org.springframework.cloud.aws.messaging.core.QueueMessageUtils.getMessageAttributesAsMessageHeaders(QueueMessageUtils.java:80)
    at org.springframework.cloud.aws.messaging.core.QueueMessageUtils.createMessage(QueueMessageUtils.java:56)
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$MessageExecutor.getMessageForExecution(SimpleMessageListenerContainer.java:375)
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$MessageExecutor.run(SimpleMessageListenerContainer.java:336)
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$SignalExecutingRunnable.run(SimpleMessageListenerContainer.java:392)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

With the problematic part being in the spring-cloud-aws-messaging module QueueMessageUtils class numberType variable assignment:

private static Object getNumberValue(MessageAttributeValue value) {
    String numberType = value.getDataType().substring("Number".length() + 1);

    try {
        Class<? extends Number> numberTypeClass = Class.forName(numberType).asSubclass(Number.class);
        return NumberUtils.parseNumber(value.getStringValue(), numberTypeClass);
    } catch (ClassNotFoundException var3) {
        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.", value.getStringValue(), value.getDataType()), var3);
    }
}

Has anyone seen this before and if so is there a way to fix this?

P.S: Since I don't really care about the message attributes I wouldn't mind if they were completely ignored.

Thanks in advance.



Solution 1:[1]

The exception in the given code is thrown from the following line.

String numberType = value.getDataType().substring("Number".length() + 1);

According to the documentation in AWS JAVA SDK,it explains how the getDataType() function works (See this link). According to the documentation, it will return one of the following values.

  • String

  • Number

  • Binary

Amazon SQS supports the following logical data types: String, Number, and Binary. For the Number data type, you must use StringValue.

Now, when you call value.getDataType(), it will return one of the above values. Assuming it's "Number", you are trying to get a substring of it, starting from index 6 (where "Number".length() + 1 = 6)

But there is no such index in the String returned by value.getDataType(). Therefore, it will throw a java.lang.StringIndexOutOfBoundsException exception.

As a solution for this, you can simply use the following instead of getting the substring of it.

String numberType = value.getDataType();

Solution 2:[2]

I have also face the same issue, when publishing message with SQS Extended Library, it automatically added one attribute along with the message SQSLargePayloadSize with the datatype Number which is causing the problem. the exception is resolved by updating the dependency from

implementation group: 'org.springframework.cloud', name: 'spring-cloud-aws-messaging', version: '2.2.6.RELEASE'

to any latest version of awspring spring-cloud-aws-messaging

implementation group: 'io.awspring.cloud', name: 'spring-cloud-aws-messaging', version: '2.4.1'

make sure all the package must be imported from io.awspring.cloud

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Keet Sugathadasa
Solution 2 Sandeep Patel