Skip to content

Fix NPE in DoubleAttributeConverter and FloatAttributeConverter for null input#6782

Open
S-Saranya1 wants to merge 3 commits intomasterfrom
somepal/fix-dynamoDB-enhanced-double-float-converter-npe
Open

Fix NPE in DoubleAttributeConverter and FloatAttributeConverter for null input#6782
S-Saranya1 wants to merge 3 commits intomasterfrom
somepal/fix-dynamoDB-enhanced-double-float-converter-npe

Conversation

@S-Saranya1
Copy link

@S-Saranya1 S-Saranya1 commented Mar 11, 2026

DoubleAttributeConverter.transformFrom() and FloatAttributeConverter.transformFrom() throw a cryptic NullPointerException (no message) when called with a null input due to
auto-unboxing in ConverterUtils.validateDouble()/validateFloat(). This occurs when users persist a Map<String, Double> or List containing null values.

Motivation and Context

The AttributeConverter.transformFrom() interface contract states it should raise a RuntimeException if the input is null. The existing code does throw, but accidentally via auto-unboxing — producing a bare NPE with no useful message. This fix replaces the accidental NPE with an explicit Validate.paramNotNull check that throws
NullPointerException with a clear "input must not be null" message.

Modifications

  • Added Validate.paramNotNull(input, "input") in ConverterUtils.validateDouble() and ConverterUtils.validateFloat()
  • Added null input tests in NumberAttributeConvertersTest for both DoubleAttributeConverter and FloatAttributeConverter, verifying exception type and message

Testing

  • Existing tests continue to pass
  • New tests verify null input throws NullPointerException with message "input must not be null"

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • My code follows the code style of this project
  • My change requires a change to the Javadoc documentation
  • I have updated the Javadoc documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed
  • I have added a changelog entry. Adding a new entry must be accomplished by running the scripts/new-change script and following the instructions. Commit the new file created by the script in .changes/next-release with your changes.
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2 license

@S-Saranya1 S-Saranya1 requested a review from a team as a code owner March 11, 2026 22:04
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
63.6% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@joviegas
Copy link
Contributor

I think one more option is to fix in the Map and list AttributeConverter to handle the null values and keys and null list objects

public EnhancedAttributeValue toAttributeValue(T input) {
Map<String, AttributeValue> result = new LinkedHashMap<>();
input.forEach((k, v) -> result.put(keyConverter.toString(k), valueConverter.transformFrom(v)));
return EnhancedAttributeValue.fromMap(result);
}

and

public AttributeValue transformFrom(T input) {
return EnhancedAttributeValue.fromListOfAttributeValues(input.stream()
.map(elementConverter::transformFrom)
.collect(toList()))
.toAttributeValue();
}

@S-Saranya1
Copy link
Author

I think one more option is to fix in the Map and list AttributeConverter to handle the null values and keys and null list objects

public EnhancedAttributeValue toAttributeValue(T input) {
Map<String, AttributeValue> result = new LinkedHashMap<>();
input.forEach((k, v) -> result.put(keyConverter.toString(k), valueConverter.transformFrom(v)));
return EnhancedAttributeValue.fromMap(result);
}

and

public AttributeValue transformFrom(T input) {
return EnhancedAttributeValue.fromListOfAttributeValues(input.stream()
.map(elementConverter::transformFrom)
.collect(toList()))
.toAttributeValue();
}

Considered fixing at the Map/List converter level, but it would introduce a behavioral change for
StringAttributeConverter and BooleanAttributeConverter. Both currently accept null values without throwing. Adding a null check at the Map/List level would break existing customers who rely on that behavior (e.g., Map<String, String> with null values). So, fixing in ConverterUtils.validateDouble()/validateFloat().

@joviegas
Copy link
Contributor

joviegas commented Mar 18, 2026

I think one more option is to fix in the Map and list AttributeConverter to handle the null values and keys and null list objects

public EnhancedAttributeValue toAttributeValue(T input) {
Map<String, AttributeValue> result = new LinkedHashMap<>();
input.forEach((k, v) -> result.put(keyConverter.toString(k), valueConverter.transformFrom(v)));
return EnhancedAttributeValue.fromMap(result);
}

and

public AttributeValue transformFrom(T input) {
return EnhancedAttributeValue.fromListOfAttributeValues(input.stream()
.map(elementConverter::transformFrom)
.collect(toList()))
.toAttributeValue();
}

Considered fixing at the Map/List converter level, but it would introduce a behavioral change for StringAttributeConverter and BooleanAttributeConverter. Both currently accept null values without throwing. Adding a null check at the Map/List level would break existing customers who rely on that behavior (e.g., Map<String, String> with null values). So, fixing in ConverterUtils.validateDouble()/validateFloat().

No I think it will not introduce behavioural change if we do as below

       public EnhancedAttributeValue toAttributeValue(T input) {
            Map<String, AttributeValue> result = new LinkedHashMap<>();
            input.forEach((k, v) -> result.put(keyConverter.toString(k),
                                                v == null ? AttributeValue.fromNul(true)
                                                          : valueConverter.transformFrom(v)));
            return EnhancedAttributeValue.fromMap(result);
        }

Here if its a null then we set to AttributeValue.fromNul(true) which is fine since user explicitly sets the value as Null and its fine sending this as Null Attributes to DDB

We can write paramaterized test to make sure this is backward compatible with all types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants