PDGGK opened a new pull request, #39731:
URL: https://github.com/apache/beam/pull/39731

   Fixes #39730.
   
   `AttributeValueCoder.encode` selected the L and M branches with a size 
check, so a DynamoDB attribute holding an **empty list** or **empty map** fell 
through to the terminal `else` and threw `CoderException("Unknown Type")`.
   
   `hasL()`/`hasM()` are the SDK's way of separating "unset" from "set but 
empty", which is exactly the distinction the size check lost.
   
   **The `ss`/`ns`/`bs` guards look identical and are deliberately left 
alone.** DynamoDB rejects empty sets, so an empty one there is not a value 
worth preserving — relaxing those would be wrong.
   
   **Blast radius.** `MAP_ATTRIBUTE_CODER` re-enters this coder for every 
child, so one empty list nested anywhere inside an item makes the whole item 
unencodable, not just that attribute. That is the realistic production trigger 
and it is what two of the new tests cover.
   
   The decode side already handles both: `case l:` and `case m:` delegate to 
`ListCoder`/`MapCoder`, which round-trip empties.
   
   ### Compatibility
   
   Wire-compatible **for every value the service can produce**. I want to be 
precise rather than overclaim: the change is *not* a no-op for a malformed 
`AttributeValue` that sets two types at once — `AttributeValue.builder().l(new 
ArrayList<>()).nul(true).build()` currently encodes as `nul` and would now 
encode as `l`. An `AttributeValue` carries exactly one type, DynamoDB never 
emits such a value, and no ordinary builder usage produces one, but the claim 
is "every value the service can produce", not "every possible value".
   
   ### Tests
   
   Five cases added to the existing `AttributeValueCoderTest`, which is a plain 
in-process encode/decode round trip — no cluster, no AWS account, no localstack.
   
   | case | on master |
   |---|---|
   | empty `L` round trip | **fails**, `CoderException: Unknown Type` |
   | empty `M` round trip | **fails** |
   | empty `L` nested in a map | **fails** — shows the parent item is lost |
   | empty `M` nested in a list | **fails** |
   | `AttributeValue.builder().build()` still rejected | passes **before and 
after** — the control |
   
   ```
   15 tests completed, 4 failed      <- on master
   BUILD SUCCESSFUL                  <- with the fix, 15/15
   ```
   
   The fifth is there so the fix cannot quietly turn "Unknown Type" into 
encoding nothing, and because it passes on both versions it also shows the 
other four are not trivially red.
   
   Each round trip asserts `hasL()`/`hasM()` on the decoded value in addition 
to equality, so a "decoded back as unset" regression would still be caught.
   
   `spotlessCheck`, `checkstyleMain` and `checkstyleTest` pass, as does the 
rest of the `dynamodb` package.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to