[JSON] Fix source generator serializing null byte[] as empty string#129834
Open
lezzi wants to merge 6 commits into
Open
[JSON] Fix source generator serializing null byte[] as empty string#129834lezzi wants to merge 6 commits into
lezzi wants to merge 6 commits into
Conversation
The source generator fast path emitted `writer.WriteBase64String(value)`
directly for byte[] members. Since byte[] implicitly converts to an empty
ReadOnlySpan<byte> when null, a null byte[] was serialized as an empty
Base64 string ("") instead of null, diverging from the reflection-based
ByteArrayConverter which writes null.
Emit an explicit null check in the fast-path serialization helpers for
JsonPrimitiveTypeKind.ByteArray, mirroring ByteArrayConverter.Write, so
that null byte[] members serialize as null for both object properties and
collection elements.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
Tagging subscribers to this area: @dotnet/area-system-text-json |
Contributor
Author
|
@dotnet-policy-service agree |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adjusts the System.Text.Json source generator’s fast-path serialization for byte[] so that null byte arrays are emitted as JSON null (rather than being treated like an empty span and written as an empty Base64 string), and extends existing nullable roundtrip tests to cover the byte[] case.
Changes:
- Emit an explicit
nullhandling branch when writingJsonPrimitiveTypeKind.ByteArrayvalues/properties in generated fast-path code. - Extend nullable roundtrip tests to include a
byte[]?property and validate both non-null and all-null instances roundtrip correctly.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs | Adds ByteArray to the nullable-properties roundtrip setup/assertions for the serialization-only context. |
| src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs | Adds ByteArray to the shared nullable-properties model and roundtrip assertions, covering the all-null regression path. |
| src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs | Updates fast-path primitive emission for ByteArray to write JSON null for null byte arrays. |
Contributor
Author
|
Will wait for issue feedback, before polishing this further. |
This was referenced Jun 25, 2026
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
- Fix indentation of else-if blocks to match surrounding code - Replace 'is byte[] __byteArray' pattern with 'is not null' to avoid local variable name collisions when a type has multiple byte[] properties Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds explicit "ByteArray":null assertions to the source-gen ClassWithNullableProperties_Roundtrip tests (covering the serialization fast path) and a new ClassWithMultipleByteArrayProperties_Roundtrip theory exercising a type with three byte[] properties to guard against emitter local-name collisions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the inline if/else null checks emitted for byte[] values in the fast-path serializer with a single on-demand `WriteByteArrayValue` private static helper on the generated context. The value is passed as a method argument so it is evaluated exactly once, avoiding the duplicate value-expression emission (and associated variable-capture concerns) of the previous inline approach. The helper is emitted only when a byte[] value is actually serialized, following the existing `_emitValueTypeSetterDelegate` on-demand pattern. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #129833
Description
The System.Text.Json source generator's fast path serialized a null
byte[]as an empty string ("") instead ofnull, diverging from the reflection-basedByteArrayConverter.This happens because the emitted
writer.WriteBase64String(value)implicitly converts the nullbyte[]to aReadOnlySpan<byte>, where null and empty are indistinguishable. UnlikeWriteString/WriteStringValue(which takestring?and null-check internally), there is noWriteBase64Stringoverload accepting a nullablebyte[]— a span can't carry null — so the check can't live in the writer call and must be emitted by the generator, mirroring whatByteArrayConverter.Writealready does.The fix adds an explicit null check in the fast-path serialization helpers for
JsonPrimitiveTypeKind.ByteArray, so nullbyte[]serializes asnullfor both object properties and collection elements.Testing
Extended
ClassWithNullableProperties_Roundtripto coverbyte[]— the existing all-null case now exercises the regression (with the bug, a nullbyte[]serialized to""round-trips back to an empty array, not null). Runs across the reflection, metadata, and serialization (fast-path) contexts.