Migrate NJsonSchema core to System.Text.Json (v12) - [WIP] - #1914
Open
RicoSuter wants to merge 11 commits into
Open
Migrate NJsonSchema core to System.Text.Json (v12) - [WIP]#1914RicoSuter wants to merge 11 commits into
RicoSuter wants to merge 11 commits into
Conversation
Migrate new FormatIpV4Tests from master (JValue -> JsonValue.Create) after merging Fix IPv4 format validator regex false positives (#1909).
…hots - Fix integer values stored as long instead of int in ConvertJsonElement (TryGetInt32 before TryGetInt64) - Remove DateTime.TryParse from extension data strings (matches Newtonsoft DateParseHandling.None behavior) - Unwrap JsonElement values in Enumeration, Default, ExclusiveMinimumRaw, ExclusiveMaximumRaw after deserialization - Add [JsonInclude] on EnumerationDescriptionsDashedRaw - Fix IsWriting flag (true during serialization, false during deserialization) - Use JavaScriptEncoder.UnsafeRelaxedJsonEscaping to match Newtonsoft output - Add JsonNumberHandling.AllowReadingFromString for schema numeric properties - Cache stripped JsonSerializerOptions in SchemaSerializationConverter - Replace non-breaking spaces (U+00A0) in FixLenientJson - Restore snapshots to match master output
…ml test Use decimal instead of double in HandleNumberType to avoid precision loss when STJ serializes doubles on .NET Framework (G17 format produces 1.0000119999999999 instead of 1.000012, failing validation). Skip Yaml gzip test that depends on NSwag.Core referencing the deleted PropertyRenameAndIgnoreSerializerContractResolver class.
… for NSwag STJ migration
SchemaSerializationConverter:
- Rewrite Write() to property-by-property serialization using typeInfo,
enabling nested types to get their own converter filters applied
- Add recursive reverse renames in Read() for nested schema properties
(e.g., nullable → x-nullable at all depth levels)
- Add IsPropertyIgnored() for JsonPathUtilities $ref path computation
- Add AddConverter() to register additional converters alongside factory
- Skip types with [JsonConverter] attribute in CanConvert()
- Cache GetAllReverseRenames() result with invalidation
- Handle extension data after regular properties with runtime type serialization
- Use runtime type for object-typed property values (prevents {} output)
JsonSchemaSerialization:
- Add Populate modifier for getter-only collection properties
- Set CurrentSerializerOptions before UpdateSchemaReferencePaths
- Save/restore CurrentSerializerOptions for nested FromJsonAsync calls
- Add Example unwrapping in PostProcessExtensionData
- Improve FixLenientJson: string boolean normalization, safer single-quote handling
- Change RequiredPropertiesRaw to object? to handle bool/array collision
Other:
- Fix visitor JsonIgnore condition check (WhenWritingDefault was incorrectly excluded)
- Add JsonElement safety net in CSharpValueGenerator.GetNumericValue
- Add IsPropertyIgnored check in JsonPathUtilities for converter-aware $ref paths
…dd migration docs - Remove Newtonsoft.Json PackageReference from NJsonSchema.csproj - Remove leftover Newtonsoft using from CodeGeneratorSettingsBase - Replace ConcurrentDictionary with ThreadStatic single-slot cache in PropertyFilterConverter - Extract PopulateTypeInfoResolver as static readonly field - Add ICollection fast-path in empty collection check - Promote ConvertJsonElement to internal, reuse in CSharpValueGenerator - Add WithAttemptingUnquotedStringTypeDeserialization in YAML deserialization - Add indexer property and value type guards in visitors and JsonPathUtilities - Bump Namotion.Reflection to 3.5.0 - Replace MIGRATION-SUMMARY.md with comprehensive migration.md and review.md
2 tasks
RicoSuter
added a commit
that referenced
this pull request
Apr 21, 2026
- New docs/changelog_v12.md tracks landed changes and v11 → v12 migration guidance per breaking change (with placeholder sections for planned PRs #1914, #1917, SchemaType expansion, reference-resolution fixes) - docs/v12.md "Running changelog" section replaced with a pointer to the dedicated file - Plan vs changelog separation: v12.md describes process (scope, branches, release plan, cleanup), changelog_v12.md is the user-facing record
RicoSuter
added a commit
that referenced
this pull request
Apr 21, 2026
* Set up v12 integration branch: plan doc and CI triggers - Add docs/v12.md describing the v12 scope, branch model, development workflow with NSwag v15, release plan, and pre-release cleanup checklist - Add v12 to OnPullRequestBranches / OnPushBranches in Build.CI.GitHubActions.cs and the regenerated workflow YAMLs so CI runs on the v12 branch and on PRs targeting it (revert before v12 merges to master) * Split v12 changelog and migration guide into docs/changelog_v12.md - New docs/changelog_v12.md tracks landed changes and v11 → v12 migration guidance per breaking change (with placeholder sections for planned PRs #1914, #1917, SchemaType expansion, reference-resolution fixes) - docs/v12.md "Running changelog" section replaced with a pointer to the dedicated file - Plan vs changelog separation: v12.md describes process (scope, branches, release plan, cleanup), changelog_v12.md is the user-facing record * Rename v12.md to plan_v12.md for parity with changelog_v12.md Plan doc and changelog are now visually paired by filename: - docs/plan_v12.md - docs/changelog_v12.md Update internal cross-references in both files. * Add CLAUDE.md and docs/references.md CLAUDE.md: - Project Overview, Cross-check with NSwag (supported spec targets table, 5-point cross-check checklist, reviewer prompt, link to references.md) - Build Commands, Architecture, Testing, Code Style - Git Rules: no AI attribution in commits / PRs / comments docs/references.md: - Comprehensive reference on ActualSchema vs ActualTypeSchema vs InheritedSchema, the resolution algorithm, and cross-spec behavior - DocumentPath / external ref resolution; $id, $anchor, $dynamicRef non-support limitations - NSwag's OpenApiParameter.ActualSchema override mechanics - Sibling-keyword gaps (the "Case C" problem), generalized beyond const - Known limitations grouped by theme; decision matrix for consumers * Enhance CLAUDE.md with project documentation index and v12 branch conventions * CLAUDE.md: drop ephemeral branch name from v12 conventions heading * Refine reference resolution fixes in changelog and plan documentation to clarify sibling-keyword handling
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.
Summary
Migrates the core
NJsonSchemapackage from Newtonsoft.Json to System.Text.Json (STJ). Newtonsoft.Json support is preserved in theNJsonSchema.NewtonsoftJsonpackage.Key changes
Core serialization
[JsonProperty]→[JsonPropertyName]+[JsonIgnore(Condition)]+[JsonInclude]$refhandling:ReferencePathchanged from explicit interface impl to[JsonInclude] internalproperty (STJ can't serialize explicit interface implementations)SchemaSerializationConverter(STJJsonConverterFactory) replaces NewtonsoftIContractResolverJToken/JObject/JArray→JsonNode/JsonObject/JsonArraythroughoutValidation
JsonSchemaValidatorusesJsonNodeinstead ofJTokenUtf8JsonReader(STJ'sJsonNodehas no line info)ValidationError.Tokenchanged fromJsonNode?toobject?to supportJsonPropertyTokenwrapperuniqueItemsvalidation for mathematical equalitySchema generation
SampleJsonDataGeneratoroutputsJsonNodeinstead ofJTokenSampleJsonSchemaGeneratorhandles lenient JSON (unquoted property names, single quotes)ReflectionServiceBaseretains Newtonsoft type names (JObject/JArray/JToken) alongside STJ equivalentsReference resolution
JsonReferenceResolveruses[JsonPropertyName]for path segment matchingPostProcessExtensionDataruns before reference resolution (refs may point into extension data)OpenApiDiscriminator.Mappingchanged to{ get; set; }for STJ deserializationBreaking API changes
ValidationError.TokenJsonNode?object?OpenApiDiscriminator.Mapping{ get; }{ get; set; }JsonSchemaSerialization.FromJsonAsyncarg 5IContractResolverSchemaSerializationConverter?PropertyRenameAndIgnoreSerializerContractResolverSchemaSerializationConverterIgnoreEmptyCollectionsContractResolverTest plan
See
MIGRATION-SUMMARY.mdfor detailed findings, workarounds, and behavioral differences.