Skip to content

Skip null check in doMarshal JSON serializer - #6807

Merged
RanVaknin merged 6 commits into
masterfrom
rvaknin/json-serializer-null-skip
Mar 30, 2026
Merged

Skip null check in doMarshal JSON serializer#6807
RanVaknin merged 6 commits into
masterfrom
rvaknin/json-serializer-null-skip

Conversation

@RanVaknin

@RanVaknin RanVaknin commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Background

During JSON serialization, JsonProtocolMarshaller.doMarshall() iterates every SdkField on a POJO and calls marshallField() for each one, including fields that are null. marshallField uses a registry to dispatch to a type specific marshaller (string, int, map, null, etc ) based on the field's value.
When the value is null, it dispatches to the NULL marshaller, that checks if the field is required (throw) or not (no-op). For non-required null fields, this entire chain (registry lookup, marshaller resolution, trait check) is wasted work.

The proposed change is to short circuit null handling for payload fields directly on the generic doMarshall() layer, and avoid the dispatch. Non payload fields still delegate to marshallField since their null marshallers have different validation logic.

Boto3's RestJson serializer handles it very similarly.

Testing

Our protocol tests already cover the main code paths of doMarshal (null headers, null query params, partial payload serialization). I added one unit test to specific JsonProtocolMarshaller directly to cover the case where a null required payload field reaches the marshaller. This codepath is caught earlier by the SDK's generated validators, but the this is just make sure the marshaller handles it correctly if that layer is ever bypassed.

Results:

Benchmarks written in #6776

Before:
image

After
image

Protocol Operation Master (ops/µs) Feature (ops/µs) Improvement
RestJson CreateFunction deser 0.176 0.175 -0.57%
RestJson CreateFunction ser 0.284 0.327 15.14%
JSON DynamoDB PutItem deser 0.141 0.141 0.00%
JSON DynamoDB PutItem ser 0.101 0.124 22.77%
CBOR CloudWatch GetMetricData deser 0.382 0.385 0.79%
CBOR CloudWatch GetMetricData ser 0.416 0.457 9.86%

@RanVaknin RanVaknin changed the title Rvaknin/json serializer null skip skip null check in doMarshal JSON serializer Mar 20, 2026
@RanVaknin RanVaknin changed the title skip null check in doMarshal JSON serializer Skip null check in doMarshal JSON serializer Mar 23, 2026
@RanVaknin
RanVaknin marked this pull request as ready for review March 23, 2026 18:28
@RanVaknin
RanVaknin requested a review from a team as a code owner March 23, 2026 18:28
import software.amazon.awssdk.protocols.json.AwsJsonProtocolMetadata;
import software.amazon.awssdk.protocols.json.internal.AwsStructuredPlainJsonFactory;

class JsonProtocolMarshallerTest {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost all of the codepaths that this file tests are covered by the protocol test package. nullPayloadField_required_throwsIllegalArgumentException is the only test that is not covered by the end to end tests because its technically not possible to get there. This codepath branch was likely added as a defense in depth.

Comment on lines +220 to +222
} else if (field.containsTrait(RequiredTrait.class, TraitType.REQUIRED_TRAIT)) {
throw new IllegalArgumentException(
String.format("Parameter '%s' must not be null", field.locationName()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we validate required client side? I thought we generally didn't do client side validation of required and instead just sent these requests to the service (since the api may have evolved and removed the required over time).

@RanVaknin RanVaknin Mar 23, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but this is not a new validation. I had to port this logic out from the null marshaller:

https://github.com/aws/aws-sdk-java-v2/blob/master/core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java#L42

since we are handling nulls now at the doMarshal level.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see - yeah, agree this makes sense here then.

@alextwoods alextwoods left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good. Needs a changelog I think.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@RanVaknin
RanVaknin added this pull request to the merge queue Mar 26, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Mar 26, 2026
@RanVaknin
RanVaknin added this pull request to the merge queue Mar 30, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Mar 30, 2026
@RanVaknin
RanVaknin added this pull request to the merge queue Mar 30, 2026
Merged via the queue into master with commit 54a01b7 Mar 30, 2026
47 of 49 checks passed
@github-actions

Copy link
Copy Markdown

This pull request has been closed and the conversation has been locked. Comments on closed PRs are hard for our team to see. If you need more assistance, please open a new issue that references this one.

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Mar 30, 2026
@RanVaknin RanVaknin added the perf-improvement Label for PRs that contain performance improvement changes. label May 21, 2026
@RanVaknin
RanVaknin deleted the rvaknin/json-serializer-null-skip branch July 20, 2026 20:07
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

perf-improvement Label for PRs that contain performance improvement changes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants