question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

DynamoDbEnhancedClient: BeanTableSchema.mapToItem returns null when given an empty map or an all-null map, should return an uninitialized bean

See original GitHub issue

Expected Behavior

A map with all null attributes, or with no non-null attributes, should return an uninitialized bean. Instead it returns null. Especially when beans contain other beans, this differences is significant and can be hard to work around.

Current Behavior

This application shows the problem. It takes an all-null bean, encodes it, then decodes it; instead of getting an all-null bean back, it gets just null:

import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;

import java.util.Map;

public class MainClass {
    @DynamoDbBean
    public static class BeanClass {
        private String name;
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    }
    public static void main(String[] args) {
        TableSchema<BeanClass> schema = TableSchema.fromBean(BeanClass.class);
        BeanClass b = new BeanClass();
        System.out.println("All-null bean cannot be decoded, returns null instead: " +
                               schema.mapToItem(schema.itemToMap(b, true)));
        System.out.println("Should print an empty bean, will print null: " +
                               schema.mapToItem(Map.of()));
    }
}

Output:

All-null bean cannot be decoded, returns null instead: null
Should print an empty bean, will print null: null

Possible Solution

The bug is in StaticImmutableTableSchema.mapToItem. It lazily constructs the bean, which means that if no setters ever need to be called, the bean is never constructed and null is returned. If it is changed to construct the bean at the start of the call, then the problem is solved.

If this seems acceptable I would be happy to write a pull request.

Steps to Reproduce (for bugs)

Compile and run the example code above.

Context

This is blocking us from moving to SDK 2. SDK 1 does not have this bug, and we do store objects with uninitialized beans, and we need to preserve the objects as-is, not null out these beans.

Your Environment

  • AWS Java SDK version used: 2.15.79
  • JDK version used: 1.3
  • Operating System and version: MacOS, and whatever AWS Lambdas runs

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
bill-phastcommented, Apr 9, 2021

Thanks so much Zoe! We appreciate your work here, it will let us switch over to SDK v2 much more easily.

If I have questions, then is it OK to ask you directly, or on github, or elsewhere? E.g., I can’t figure out why DynamoDbTable.query() returns a PageIterable, but DynamoDbIndex.query() returns a SdkIterable<Page>. It would be much more straightforward if they returned the same thing. (It would be really nice if Table and Index were the same class, so we could use primary indexes and GSIs interchangeably in the code, but it doesn’t seem to be set up that way.)

On Thu, Apr 8, 2021 at 4:19 PM Zoe Wang @.***> wrote:

Hi @bill-phast https://github.com/bill-phast , @reed53 https://github.com/reed53 thank you for your patience!

This feature has been implemented via #2364 https://github.com/aws/aws-sdk-java-v2/pull/2364. The PR has been merged, and the change will be included in the next release. To ensure the inner beans are converted to empty object, you just need to add DynamoDbPreserveEmptyObject on the getter methods of that inner beans.

https://github.com/aws/aws-sdk-java-v2/blob/c7d5302095df71e5579c7026912f508f4556f2cd/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/mapper/annotations/DynamoDbPreserveEmptyObject.java#L78

@DynamoDbBeanpublic class Case {

private String id;

public Qc qc;

@DynamoDbPartitionKey
public String getId() {
    return id;
}
public void setId(String id) {
    this.id = id;
}

@DynamoDbPreserveEmptyObject
public Qc getQc() {
    return qc;
}
public void setQc(Qc qc) {
    this.qc = qc;
}

}

Please let us know if you have any questions.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/aws/aws-sdk-java-v2/issues/2280#issuecomment-816150106, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQDOVN556D2ISKHFGEQZ44LTHYFVVANCNFSM4XPJHXNQ .

0reactions
github-actions[bot]commented, Jul 21, 2021

⚠️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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

DynamoDbEnhancedClient: BeanTableSchema.mapToItem returns ...
Expected Behavior. A map with all null attributes, or with no non-null attributes, should return an uninitialized bean. Instead it returns null.
Read more >
TableSchema (AWS SDK for Java - 2.18.37)
If all attribute values in the attributeMap are null, null will be returned. Use mapToItem(Map, boolean) instead if you need to preserve empty...
Read more >
How to skip over an element in .map()? - Stack Overflow
Just .filter() it first: var sources = images.filter(function(img) { if (img.src.split('.').pop() === "json") { return false; // skip } return true; }) ...
Read more >
TableSchema (AWS Java SDK :: DynamoDB - javadoc.io
Scans a bean class that has been annotated with DynamoDb bean annotations and then returns a BeanTableSchema implementation of this interface that can...
Read more >
How to use remove method in java.util.Map - Tabnine
Returns whether this Map contains the specified key. keySet. Returns a set of the keys contained in this Map. The Set is backed...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found