feat(stjm): support .NET 8 and .NET 9 without JSON upgrades - #280
LiteracyFanatic wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The .NET 8 resolver test no longer exercises its named cycle scenario, and compatibility documentation remains contradictory.
Review effort: Balanced
Findings: 1
Open (3)
What changed in this PR
Adds a .NET 8 package asset without requiring a newer System.Text.Json, while retaining .NET 10/11 behavior.
Changes:
- Multi-targets library, tests, samples, and benchmarks for .NET 8.
- Accesses internal .NET 8 collection metadata for routing compatibility.
- Expands routing tests, CI, analyzer, trimming, and NativeAOT validation.
| File | Description |
|---|---|
.github/workflows/egil-systemtextjson-migration-ci.yml |
Adds .NET 8 CI coverage. |
Egil.SystemTextJson.Migration/AGENTS.md |
Documents supported frameworks. |
Egil.SystemTextJson.Migration/README.md |
Announces .NET 8 support. |
Egil.SystemTextJson.Migration/docs/recipes/aot-source-gen.md |
Documents the .NET 8 resolver workaround. |
Egil.SystemTextJson.Migration/perf/Egil.SystemTextJson.Migration.PerfTests/Egil.SystemTextJson.Migration.PerfTests.csproj |
Adds the .NET 8 benchmark target. |
Egil.SystemTextJson.Migration/samples/Egil.SystemTextJson.Migration.Samples/Egil.SystemTextJson.Migration.Samples.csproj |
Adds the .NET 8 sample target. |
Egil.SystemTextJson.Migration/scripts/verify-analyzer-package.ps1 |
Parameterizes analyzer verification by framework. |
Egil.SystemTextJson.Migration/scripts/verify-trimming-package.ps1 |
Verifies all three framework assets. |
Egil.SystemTextJson.Migration/src/Egil.SystemTextJson.Migration/Egil.SystemTextJson.Migration.csproj |
Adds the .NET 8 package asset. |
Egil.SystemTextJson.Migration/src/Egil.SystemTextJson.Migration/Migrations/SourceValueShape.cs |
Uses the compatibility accessor on .NET 8. |
Egil.SystemTextJson.Migration/src/Egil.SystemTextJson.Migration/Migrations/StjInternals.cs |
Adds access to internal collection metadata. |
Egil.SystemTextJson.Migration/test/Egil.SystemTextJson.Migration.Analyzers.Tests/Egil.SystemTextJson.Migration.Analyzers.Tests.csproj |
Runs analyzer tests on .NET 8. |
Egil.SystemTextJson.Migration/test/Egil.SystemTextJson.Migration.Tests/CollectionContractCompatibilityTests.cs |
Adds collection-routing compatibility coverage. |
Egil.SystemTextJson.Migration/test/Egil.SystemTextJson.Migration.Tests/Egil.SystemTextJson.Migration.Tests.csproj |
Runs runtime tests on .NET 8. |
Egil.SystemTextJson.Migration/test/Egil.SystemTextJson.Migration.Tests/ResolverChainTests.cs |
Adapts resolver setup for .NET 8. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
5d90e7b to
e593fc1
Compare
egil
left a comment
There was a problem hiding this comment.
One CI concern: out-of-support warnings for net8.0/net9.0 after .NET 11 GA. Suggested fix inline. The library changes look correct.
Generated by Claude Code
| dotnet pack ./src/Egil.SystemTextJson.Migration/Egil.SystemTextJson.Migration.csproj -c Release --no-build --output ${{ env.NuGetDirectory }} | ||
| pwsh -NoProfile -File ./scripts/verify-analyzer-package.ps1 -PackagePath "$(find ${{ env.NuGetDirectory }} -maxdepth 1 -name '*.nupkg' -print -quit)" | ||
| # setup-dotnet installs SDKs in this job; this script verifies one target per call. | ||
| for framework in net8.0 net9.0 net10.0 net11.0; do |
There was a problem hiding this comment.
CI will likely break when .NET 8 and 9 go out of support (2026-11-10, same day as .NET 11 GA).
- After the SDK pin moves to
11.0.x(per the workflow comment),global.jsonrolls forward to that SDK. - It will likely emit NETSDK1138 (target framework out of support) for
net8.0andnet9.0. - This loop builds the consumers with
-warnaserror, and Release builds setTreatWarningsAsErrorsin the rootDirectory.Build.props, so that warning becomes an error. SDK 9.0.100 did the same tonet6.0on its release day.
Suggested fix: opt out of the check with the documented CheckEolTargetFramework property. It states intent better than adding NETSDK1138 to NoWarn.
- Library/test/perf/sample projects: add it to the root
Directory.Build.props(or to a package-level one, if you'd rather keep it scoped to this package):<PropertyGroup Label="Compile settings"> <!-- Deliberately keep targeting out-of-support TFMs (net8.0, net9.0). --> <CheckEolTargetFramework>false</CheckEolTargetFramework> </PropertyGroup>
- Generated consumer projects: these don't pick up the repo props.
verify-analyzer-package.ps1writes them to a temp dir, andverify-trimming-package.ps1stubs outDirectory.Build.props. So add the property inline to each generated<PropertyGroup>:Consumer.csproj,InvalidConsumer.csprojandSeverityConsumer.csprojinverify-analyzer-package.ps1, plus the trimming consumer inverify-trimming-package.ps1:(Alternative: pass<CheckEolTargetFramework>false</CheckEolTargetFramework>
-p:CheckEolTargetFramework=falseto eachdotnet restore/build/publishcall in the scripts.)
Generated by Claude Code
There was a problem hiding this comment.
Added CheckEolTargetFramework=false in package-level Directory.Build.props, which explicitly imports the root props so existing build settings remain intact. It is also inline in all three analyzer consumer projects and the trimming/AOT consumer project. Other packages retain their existing SDK support checks.
The Release solution build passed on all four targets with zero warnings/errors. I simulated SDK end-of-support checks for .NET 8/9 across the package projects and all four generated consumer templates: the new settings passed, while controls with CheckEolTargetFramework=true failed with NETSDK1138.
Updated in 87b1f31; the PR still contains one commit.
Add .NET 8 and .NET 9 assets so applications and plugin hosts can use migration support with their framework-provided System.Text.Json. Read resolved collection metadata through a .NET 8-only accessor; .NET 9 and newer retain the public API path. Preserve collection-routing behavior and cover resolver snapshot retention and cyclic discovery on the applicable runtimes. Keep compatibility guidance consistent and extend CI and packed-consumer verification across all supported targets without changing other packages or shared dependency versions. Keep the retained framework assets buildable with newer SDKs after their support end dates by disabling framework end-of-support checks within this package and its isolated verification consumers.
e593fc1 to
87b1f31
Compare


.NET 8 and .NET 9 applications currently cannot consume the migration package. Adding a newer System.Text.Json package would also force a dependency upgrade in hosts that already load JSON 8. In a Civil 3D 2025 host test, that approach failed with FileLoadException for System.Text.Json 10.0.0.0; the new net8.0 asset passed using the host's existing JSON 8 assembly.
Add net8.0 and net9.0 alongside net10.0 and net11.0 across the migration library, tests, samples, and benchmarks. The only runtime compatibility branch reads JsonTypeInfo.ElementType through the existing StjInternals UnsafeAccessor pattern on .NET 8, where this property is internal. Reading the resolved JSON contract preserves collection routing semantics, including inherited collections with multiple IEnumerable interfaces, without duplicating System.Text.Json's converter-selection rules or adding a runtime package dependency. The .NET 9 and newer assets use the public property path; union support remains .NET 11-only.
Add 36 collection-routing cases and separate resolver snapshot retention, newer-runtime decorator retention, and actual cycle termination on .NET 8/9. Document the snapshot-before-decoration pattern and keep linked compatibility guidance consistent. Extend CI to install .NET 8 and .NET 9, run all supported targets, and verify packaged analyzers and trimming/NativeAOT diagnostics on each target. The analyzer package check explicitly loops over consumer frameworks; multi-target solution builds and tests are handled by MSBuild. Disable CheckEolTargetFramework within the migration package and each isolated verification consumer so newer SDKs do not reject the retained targets after their support end dates. The package-level props import the repository defaults; other packages retain their existing policy.
Validation:
Other packages are unaffected: they do not reference the migration library, and this change does not edit their targets, workflows, central dependency versions, or shared build settings.