diff --git a/.changes/next-release/bugfix-AmazonDynamoDBEnhancedClient-converter-utils-npe.json b/.changes/next-release/bugfix-AmazonDynamoDBEnhancedClient-converter-utils-npe.json new file mode 100644 index 000000000000..e32543dee384 --- /dev/null +++ b/.changes/next-release/bugfix-AmazonDynamoDBEnhancedClient-converter-utils-npe.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "Amazon DynamoDB Enhanced Client", + "contributor": "", + "description": "Fix NullPointerException in `ConverterUtils.validateDouble()` and `ConverterUtils.validateFloat()` when input is null." +} diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/converter/ConverterUtils.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/converter/ConverterUtils.java index 0f6f20583187..ee1f001641f5 100644 --- a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/converter/ConverterUtils.java +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/converter/ConverterUtils.java @@ -36,18 +36,24 @@ private ConverterUtils() { /** * Validates that a given Double input is a valid double supported by {@link DoubleAttributeConverter}. - * @param input + * @param input the Double value to validate, may be null */ public static void validateDouble(Double input) { + if (input == null) { + return; + } Validate.isTrue(!Double.isNaN(input), "NaN is not supported by the default converters."); Validate.isTrue(Double.isFinite(input), "Infinite numbers are not supported by the default converters."); } /** - * Validates that a given Float input is a valid double supported by {@link FloatAttributeConverter}. - * @param input + * Validates that a given Float input is a valid float supported by {@link FloatAttributeConverter}. + * @param input the Float value to validate, may be null */ public static void validateFloat(Float input) { + if (input == null) { + return; + } Validate.isTrue(!Float.isNaN(input), "NaN is not supported by the default converters."); Validate.isTrue(Float.isFinite(input), "Infinite numbers are not supported by the default converters."); } diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/converter/ConverterUtilsTest.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/converter/ConverterUtilsTest.java new file mode 100644 index 000000000000..c50f4877fbb7 --- /dev/null +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/converter/ConverterUtilsTest.java @@ -0,0 +1,90 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.enhanced.dynamodb.internal.converter; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.Test; + +class ConverterUtilsTest { + + @Test + void validateDouble_withNull_doesNotThrowException() { + assertThatCode(() -> ConverterUtils.validateDouble(null)) + .doesNotThrowAnyException(); + } + + @Test + void validateDouble_withValidValue_doesNotThrowException() { + assertThatCode(() -> ConverterUtils.validateDouble(1.5)) + .doesNotThrowAnyException(); + } + + @Test + void validateDouble_withNaN_throwsException() { + assertThatThrownBy(() -> ConverterUtils.validateDouble(Double.NaN)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("NaN is not supported"); + } + + @Test + void validateDouble_withPositiveInfinity_throwsException() { + assertThatThrownBy(() -> ConverterUtils.validateDouble(Double.POSITIVE_INFINITY)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Infinite numbers are not supported"); + } + + @Test + void validateDouble_withNegativeInfinity_throwsException() { + assertThatThrownBy(() -> ConverterUtils.validateDouble(Double.NEGATIVE_INFINITY)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Infinite numbers are not supported"); + } + + @Test + void validateFloat_withNull_doesNotThrowException() { + assertThatCode(() -> ConverterUtils.validateFloat(null)) + .doesNotThrowAnyException(); + } + + @Test + void validateFloat_withValidValue_doesNotThrowException() { + assertThatCode(() -> ConverterUtils.validateFloat(1.5f)) + .doesNotThrowAnyException(); + } + + @Test + void validateFloat_withNaN_throwsException() { + assertThatThrownBy(() -> ConverterUtils.validateFloat(Float.NaN)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("NaN is not supported"); + } + + @Test + void validateFloat_withPositiveInfinity_throwsException() { + assertThatThrownBy(() -> ConverterUtils.validateFloat(Float.POSITIVE_INFINITY)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Infinite numbers are not supported"); + } + + @Test + void validateFloat_withNegativeInfinity_throwsException() { + assertThatThrownBy(() -> ConverterUtils.validateFloat(Float.NEGATIVE_INFINITY)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Infinite numbers are not supported"); + } +}