Skip to content

Migrate NJsonSchema core to System.Text.Json (v12)#1914

Open
RicoSuter wants to merge 7 commits intomasterfrom
feature/migrate-core-to-stj
Open

Migrate NJsonSchema core to System.Text.Json (v12)#1914
RicoSuter wants to merge 7 commits intomasterfrom
feature/migrate-core-to-stj

Conversation

@RicoSuter
Copy link
Copy Markdown
Owner

@RicoSuter RicoSuter commented Mar 8, 2026

Summary

Migrates the core NJsonSchema package from Newtonsoft.Json to System.Text.Json (STJ). Newtonsoft.Json support is preserved in the NJsonSchema.NewtonsoftJson package.

  • Zero Newtonsoft.Json references in NJsonSchema core production code
  • All 520 tests passing (519 original + 1 new), 0 failing
  • Demo matches master exactly (248 passes, 10 fails, 8 exceptions)
  • Full solution builds clean across all target frameworks (netstandard2.0, net462, net8.0)

Key changes

Core serialization

  • All [JsonProperty][JsonPropertyName] + [JsonIgnore(Condition)] + [JsonInclude]
  • $ref handling: ReferencePath changed from explicit interface impl to [JsonInclude] internal property (STJ can't serialize explicit interface implementations)
  • New SchemaSerializationConverter (STJ JsonConverterFactory) replaces Newtonsoft IContractResolver
  • JToken/JObject/JArrayJsonNode/JsonObject/JsonArray throughout

Validation

  • JsonSchemaValidator uses JsonNode instead of JToken
  • Line information tracking reimplemented using Utf8JsonReader (STJ's JsonNode has no line info)
  • ValidationError.Token changed from JsonNode? to object? to support JsonPropertyToken wrapper
  • Number normalization in uniqueItems validation for mathematical equality

Schema generation

  • SampleJsonDataGenerator outputs JsonNode instead of JToken
  • SampleJsonSchemaGenerator handles lenient JSON (unquoted property names, single quotes)
  • ReflectionServiceBase retains Newtonsoft type names (JObject/JArray/JToken) alongside STJ equivalents

Reference resolution

  • JsonReferenceResolver uses [JsonPropertyName] for path segment matching
  • PostProcessExtensionData runs before reference resolution (refs may point into extension data)
  • OpenApiDiscriminator.Mapping changed to { get; set; } for STJ deserialization

Breaking API changes

Change Old New
ValidationError.Token JsonNode? object?
OpenApiDiscriminator.Mapping { get; } { get; set; }
JsonSchemaSerialization.FromJsonAsync arg 5 IContractResolver SchemaSerializationConverter?
Deleted PropertyRenameAndIgnoreSerializerContractResolver SchemaSerializationConverter
Deleted IgnoreEmptyCollectionsContractResolver Removed

Test plan

  • NJsonSchema.Tests: 520 passed, 0 failed, 7 skipped (net8.0)
  • Solution builds clean on all TFMs (netstandard2.0, net462, net8.0)
  • NJsonSchema.Demo matches master output (248/10/8)
  • Run full CI across all test projects and frameworks
  • Verify NSwag integration

See MIGRATION-SUMMARY.md for detailed findings, workarounds, and behavioral differences.

@RicoSuter RicoSuter changed the title Migrate NJsonSchema to System.Text.Json [WIP] Migrate NJsonSchema core to System.Text.Json Mar 29, 2026
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.
@RicoSuter RicoSuter changed the title Migrate NJsonSchema core to System.Text.Json Migrate NJsonSchema core to System.Text.Json (v12) Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant