Skip to content

System.Text.Json conversion for template engine project and tests#54022

Merged
NikolaMilosavljevic merged 3 commits intodotnet:mainfrom
NikolaMilosavljevic:te.stj
Apr 24, 2026
Merged

System.Text.Json conversion for template engine project and tests#54022
NikolaMilosavljevic merged 3 commits intodotnet:mainfrom
NikolaMilosavljevic:te.stj

Conversation

@NikolaMilosavljevic
Copy link
Copy Markdown
Member

@NikolaMilosavljevic NikolaMilosavljevic commented Apr 21, 2026

Newtonsoft.Json → System.Text.Json Migration: Microsoft.TemplateEngine.Cli

Overview

Migrated src/Cli/Microsoft.TemplateEngine.Cli from Newtonsoft.Json (JObject, JToken, JArray, etc.) to System.Text.Json (JsonNode, JsonObject, JsonArray, JsonValue). The project has <IsAotCompatible>true</IsAotCompatible>, so all serialization avoids reflection-based APIs.

Files Changed

Source (8 files)

File Key Changes
JExtensions.cs Full rewrite. ReadObject() returns JsonObject, WriteObject() uses Utf8JsonWriter. TryParse() returns JsonNode?. Added GetPropertyCaseInsensitive() helper.
AliasModel.cs [JsonProperty][JsonInclude] on public properties.
AliasRegistry.cs Save() builds JsonObject/JsonArray manually (AOT-safe). ToStringListDictionary() uses case-insensitive property lookup matching original Newtonsoft behavior.
HostSpecificTemplateData.cs Constructor takes JsonObject?. Boolean values handled via JsonValueKind.True/False switch. Custom JsonConverter rewritten with Utf8JsonWriter. UsageExamples parsing filters by JsonValueKind.String before calling GetValue<string>().
HostSpecificDataLoader.cs JObject.ParseJsonNode.Parse()?.AsObject(). Both string and stream parse paths use JsonDocumentOptions with CommentHandling = Skip and AllowTrailingCommas = true.
CliHostSearchCacheData.cs JObjectJsonObject. Property detection uses HashSet<string> with OrdinalIgnoreCase for O(1) lookup instead of nested LINQ.
ChmodPostActionProcessor.cs JArray.ParseJsonNode.Parse().AsArray().
PostActionProcessorBase.cs Token type checks use JsonValueKind enum.

Tests (3 files)

File Key Changes
AliasAssignmentTests.cs JObject.ParseJsonNode.Parse. Typed GetValue<string>()/GetValue<bool>() for value extraction.
HostDataLoaderTests.cs JObject.FromObjectJsonSerializer.SerializeToNode. Property assertions rewritten for JsonObject.
TemplateSearchCoordinatorTests.cs JObject.FromObject(cache).ToString()JsonSerializer.Serialize(cache).

Notable Design Decisions

  1. No JsonSerializer.Serialize<T>() in production code — all serialization uses Utf8JsonWriter manual writes or JsonNode.WriteTo() to remain AOT-compatible.

  2. JsonArray.Add((JsonNode)JsonValue.Create(item)!) pattern — generic Add<T> triggers AOT warnings; explicit cast avoids them.

  3. Case-insensitive property access — Newtonsoft property access was case-insensitive by default. STJ's JsonObject is case-sensitive, so GetPropertyCaseInsensitive() helpers and manual iteration were added where backward compatibility matters (e.g., AliasRegistry.ToStringListDictionary, HostSpecificTemplateData constructor).

  4. JsonDocumentOptions for lenient parsingHostSpecificDataLoader and JExtensions.TryParse() explicitly opt into comment skipping and trailing commas, matching the permissive parsing behavior of Newtonsoft's defaults.

  5. Defensive value extractionUsageExamples filters elements by JsonValueKind.String before calling GetValue<string>() to avoid InvalidOperationException on unexpected element types.

  6. O(1) property detectionCliHostSearchCacheData builds a HashSet<string>(StringComparer.OrdinalIgnoreCase) from cache keys once, replacing a nested O(n×m) LINQ query.

Verification

  • Build: 0 errors, 0 warnings (AOT-compatible)
  • Tests: 773 passed, 0 failed, 6 skipped (pre-existing skips)

Copilot AI review requested due to automatic review settings April 21, 2026 19:10
@NikolaMilosavljevic NikolaMilosavljevic requested a review from a team as a code owner April 21, 2026 19:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Migrates Microsoft.TemplateEngine.Cli and its unit tests off the transitive Newtonsoft.Json dependency and onto System.Text.Json, including replacing JObject/JToken usage with JsonNode/JsonObject and updating serialization/deserialization paths to be AOT-safe.

Changes:

  • Rewrote CLI JSON helper extensions (JExtensions) for System.Text.Json.Nodes and updated consumers.
  • Updated host-specific template data loading/serialization and CLI host cache parsing to use STJ nodes.
  • Updated alias persistence and unit tests to use STJ serialization APIs.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
test/Microsoft.TemplateEngine.Cli.UnitTests/TemplateSearchCoordinatorTests.cs Switches cache JSON creation from JObject.FromObject to JsonSerializer.Serialize.
test/Microsoft.TemplateEngine.Cli.UnitTests/HostDataLoaderTests.cs Updates serialization/assertions to use JsonSerializer.SerializeToNode and JsonObject APIs.
test/Microsoft.TemplateEngine.Cli.UnitTests/AliasAssignmentTests.cs Moves test parsing/assertions from JObject/JValue to JsonNode + typed GetValue<T>().
src/Cli/Microsoft.TemplateEngine.Cli/TemplateSearch/CliHostSearchCacheData.cs Ports cache additional-data reader from JObject to JsonObject.
src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/PostActionProcessorBase.cs Ports JSON parsing for targetFiles from JToken/JArray to JsonNode/JsonArray.
src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/ChmodPostActionProcessor.cs Ports chmod args parsing from JArray.Parse to JsonNode.Parse().AsArray().
src/Cli/Microsoft.TemplateEngine.Cli/JExtensions.cs Replaces Newtonsoft-based helper extensions with System.Text.Json node-based helpers and file read/write.
src/Cli/Microsoft.TemplateEngine.Cli/HostSpecificTemplateData.cs Ports host data model parsing and custom converter to System.Text.Json and AOT-safe writing.
src/Cli/Microsoft.TemplateEngine.Cli/HostSpecificDataLoader.cs Switches host JSON reading from JsonTextReader/JObject.Load to JsonNode.Parse.
src/Cli/Microsoft.TemplateEngine.Cli/Alias/AliasRegistry.cs Updates alias file read/write to use JsonObject and writes JSON via JExtensions.WriteObject.
src/Cli/Microsoft.TemplateEngine.Cli/Alias/AliasModel.cs Replaces [JsonProperty] with [JsonInclude] (STJ attribute).

Comment thread src/Cli/Microsoft.TemplateEngine.Cli/TemplateSearch/CliHostSearchCacheData.cs Outdated
Comment thread src/Cli/Microsoft.TemplateEngine.Cli/Alias/AliasRegistry.cs Outdated
Comment thread src/Cli/Microsoft.TemplateEngine.Cli/HostSpecificDataLoader.cs
Comment thread src/Cli/Microsoft.TemplateEngine.Cli/HostSpecificDataLoader.cs
Comment thread src/Cli/Microsoft.TemplateEngine.Cli/HostSpecificTemplateData.cs Outdated
@NikolaMilosavljevic
Copy link
Copy Markdown
Member Author

Failures are unrelated and known issues.

@NikolaMilosavljevic NikolaMilosavljevic merged commit 9bf8092 into dotnet:main Apr 24, 2026
20 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants