Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AttributeValue does not get serialized/deserialized correctly #4107

Closed
ndodda-amazon opened this issue Jun 15, 2023 · 2 comments
Closed

AttributeValue does not get serialized/deserialized correctly #4107

ndodda-amazon opened this issue Jun 15, 2023 · 2 comments
Assignees
Labels
bug This issue is a bug. dynamodb-enhanced

Comments

@ndodda-amazon
Copy link

Describe the bug

I have a requirement where I need to be able to serialize a DynamoDB item to a string and then deserialize it as an item again. I do the serialization by creating a TableSchema object, calling itemToMap, and then using Gson to convert the map to a JSON string. Similarly, I do the deserialization by converting the string to a map and then calling mapToItem from the same table schema to get the item.

However, when the serialization occurs, the JSON string for an attribute value looks like the following:

"dimensions":{"ss":[],"ns":[],"bs":[],"m":{},"l":["name":{"s":"name","ss":[],"ns":[],"bs":[],"m":{},"l":[],"type":"S"}},"l":[],"type":"M"}],"type":"L"}

where this corresponds to a list of Dimension objects, which looks like:

@DynamoDbBean
data class Dimension(var name: String? = null)

The issue here is that other collections in the attribute value get initialized as an empty data structure, instead of not being initialized in the first place. This leads to an error during deserialization when using the ListAttributeConverter.

Expected Behavior

I expected that the ListAttributeConverter can convert lists of custom objects correctly and deserialize the JSON as an object correctly.

Current Behavior

Instead it fails with the following error:

software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.ListAttributeConverter cannot convert an attribute of type M into the requested type interface java.util.List
java.lang.IllegalStateException: software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.ListAttributeConverter cannot convert an attribute of type M into the requested type interface java.util.List
	at software.amazon.awssdk.enhanced.dynamodb.internal.converter.TypeConvertingVisitor.defaultConvert(TypeConvertingVisitor.java:188)
	at software.amazon.awssdk.enhanced.dynamodb.internal.converter.TypeConvertingVisitor.convertMap(TypeConvertingVisitor.java:113)
	at software.amazon.awssdk.enhanced.dynamodb.internal.converter.TypeConvertingVisitor.convert(TypeConvertingVisitor.java:88)
	at software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.EnhancedAttributeValue.convert(EnhancedAttributeValue.java:428)
	at software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.ListAttributeConverter$Delegate.transformTo(ListAttributeConverter.java:156)
	at software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.ListAttributeConverter.transformTo(ListAttributeConverter.java:121)
	at software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute.ListAttributeConverter.transformTo(ListAttributeConverter.java:83)

This is because when the enhanced attribute value is trying to determine how to parse the attribute value (ref),

if (attributeValue.hasM()) {
            return EnhancedAttributeValue.fromMap(attributeValue.m());
        }

hasM returns true and it fails to parse the list as a map. hasM returns True, because it checks if m is null instead of empty.

Reproduction Steps

  1. Create an attribute value of type list
  2. Serialize the attribute value using Gson.toJson
  3. Deserialize the attribute value using Gson.fromJson
  4. Call EnhancedAttributeValue.fromAttributeValue to reproduce the failure

Possible Solution

Two quick fixes:

  1. Use a switch statement on the attribute value type instead of using the boolean functions
  2. Modify hasM to check if the field is an empty dictionary

Long term - I don't think it makes sense to even allow a state where an attribute value has multiple values. It probably makes more sense to throw an error if we attempt to set multiple values.

Additional Information/Context

This may be an issue in the serialization itself (i.e. why are multiple fields written for each attribute value). If this isn't the correct way to serialize an AttributeValue as a JSON, please suggest an alternative method.

AWS Java SDK version used

2.20.40

JDK version used

11

Operating System and version

MacOS Ventura 13.4

@ndodda-amazon ndodda-amazon added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Jun 15, 2023
@debora-ito debora-ito added needs-review This issue or PR needs review from the team. dynamodb-enhanced and removed needs-triage This issue or PR still needs to be triaged. needs-review This issue or PR needs review from the team. labels Jul 18, 2023
@debora-ito debora-ito self-assigned this Jul 22, 2023
@debora-ito
Copy link
Member

@ndodda-amazon we don't consider this a bug, it's a use case we don't support. Initializing the attributes with empty values was a design decision of the DDB Enhanced Client. Also, I don't think we can change hasM to check for empty values without doing a breaking change.

We do have a open feature request to support a native JSON attribute converter, feel free to add a 👍 - #2162

@debora-ito debora-ito closed this as not planned Won't fix, can't repro, duplicate, stale Jul 22, 2023
@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue is a bug. dynamodb-enhanced
Projects
None yet
Development

No branches or pull requests

2 participants