Description
Describe the bug
When calling TableSchema.itemToMap() method to convert a table bean into a map of names/attributes, the ignoreNulls flag is not propagated to nested beans.
Expected Behavior
The generated map should not contains any AttributeValue with nul=true even in nested maps.
Current Behavior
Currently, converting items to maps with ignoreNulls=true might generate AttributeValue with nul=true elements.
Steps to Reproduce
public static final StaticTableSchema CHAPTER_SCHEMA = StaticTableSchema.builder(Chapter.class)
.newItemSupplier(Chapter::new)
.addAttribute(Integer.class, a -> a.name("page").getter(Chapter::getPage).setter(Chapter::setPage))
.addAttribute(String.class, a -> a.name("text").getter(Chapter::getText).setter(Chapter::setText))
.build();
public static final StaticTableSchema BOOK_SCHEMA = StaticTableSchema.builder(Book.class)
.newItemSupplier(Book::new)
.addAttribute(String.class, a -> a.name("id").tags(primaryPartitionKey()).getter(Book::getId).setter(Book::setId))
.addAttribute(EnhancedType.documentOf(Chapter.class, CHAPTER_SCHEMA),
a -> a.name("chapter").getter(Book::getChapter).setter(Book::setChapter))
.addAttribute(EnhancedType.mapOf(EnhancedType.of(String.class), EnhancedType.documentOf(Chapter.class, CHAPTER_SCHEMA)),
a -> a.name("chapters").getter(Book::getChapters).setter(Book::setChapters))
.build();
@DynamoDbBean
public static class Book {
private String id;
private Chapter chapter;
private Map<String, Chapter> chapters;
public Book() { }
public Book(String id) { setId(id); }
@DynamoDbPartitionKey
public String getId() {return id;}
public void setId(String id) {this.id = id;}
public Chapter getChapter() {return chapter;}
public void setChapter(Chapter chapter) {this.chapter = chapter;}
public Map<String, Chapter> getChapters() {return chapters;}
public void setChapters(Map<String, Chapter> chapters) {this.chapters = chapters;}
}
@DynamoDbBean
public static class Chapter {
private Integer page;
private String text;
public Integer getPage() {return page;}
public void setPage(Integer page) {this.page = page;}
public String getText() {return text;}
public void setText(String text) {this.text = text;}
}
@test
public void testStatic() throws Exception {
DynamoDbEnhancedClient enhancedClient = getEnhancedClient();
DynamoDbTable table = enhancedClient.table("books", BOOK_SCHEMA);
table.createTable();
Chapter chapter = new Chapter();
chapter.setPage(1);
Book book = new Book("123");
book.setChapter(chapter);
book.setChapters(Collections.singletonMap("First", chapter));
Map<String, AttributeValue> map = table.tableSchema().itemToMap(book, true);
assertNull(map.get("chapter").m().get("text"));
}
@test
public void testBean() throws Exception {
DynamoDbEnhancedClient enhancedClient = getEnhancedClient();
DynamoDbTable table = enhancedClient.table("books", TableSchema.fromBean(Book.class));
table.createTable();
Chapter chapter = new Chapter();
chapter.setPage(1);
Book book = new Book("123");
book.setChapter(chapter);
book.setChapters(Collections.singletonMap("First", chapter));
Map<String, AttributeValue> map = table.tableSchema().itemToMap(book, true);
assertNull(map.get("chapter").m().get("text"));
}
Possible Solution
The ignoreNulls flag is simply not propagated when the conversion is applied. I'm aware it is possible to add DynamoDbIgnoreNulls annotations or explicitly override the EnhancedTypeDocumentConfiguration in static schema construction, but that completely defeats the purpose of having a conversion method with an ignoreNulls parameter.
Calling TableSchema.itemToMap() with ignoreNulls= true should override any statically defined configuration.