Skip to main content

NewtonsoftParityInt32Converter

Namespace: Meshmakers.Octo.Sdk.Common.EtlDataPipeline

Read-side parity twin of NewtonsoftParityDoubleConverter for Int32.

public sealed class NewtonsoftParityInt32Converter : JsonConverter<Int32>

Inheritance Object → JsonConverter → JsonConverter<Int32> → NewtonsoftParityInt32Converter

Remarks:

System.Text.Json's built-in Int32 converter inspects the raw text of a number token: reader.GetInt32() rejects the literal 5.0 even though the value is integral. Newtonsoft's (int)JToken instead goes through Convert.ToInt32(double, InvariantCulture) and accepts it.

That matters because the write side deliberately emits a trailing .0 for every integral double (see NewtonsoftParityDoubleConverter: a double 0.0 written as the JSON literal 0 would round-trip back as Int64 and land in MongoDB as a BsonInt64 where Newtonsoft stored a BsonDouble). So every node that writes a double — Math@1, LinearScaler@1, SumAggregation@1, ConvertDataType@1 to Double, ExecuteCSharp@1 returning a double — stores 5.0, and every downstream Get<int> on it threw. The strict built-in is a parity regression from the Newtonsoft to System.Text.Json migration, not a designed contract (AB#5275).

Coercion rules, verified against the Newtonsoft oracle by Sdk.Common.PipelineParityTests.IntegerCoercionParityTests:

exact integral literal — built-in fast path, no coercion, no precision loss

real literal or exponent — banker's rounding (MidpointRounding.ToEven), matching Convert.ToInt32(double): 5.0 to 5, 5.7 to 6, 5.5 to 6, 4.5 to 4, -5.5 to -6

JSON string — honors , integer first and then real-tolerant

out of range or NaN — , deliberately NOT OverflowException (which is what Convert.ToInt32 would throw), because DateTimeNode catches to build its own InvalidUnixTimestamp error

This does NOT touch JsonScalar.ToClr, the dynamic boxing path behind IDataContext.GetValue() and RtAttributesConverter. Its contract is explicitly "reals stay double"; coercing there would bring the BsonInt64 regression back. Only explicitly typed reads change.

Two deliberate divergences from the oracle, pinned by the parity suite: a quoted real ("5.0") coerces here but throws in Newtonsoft, so the quoted and unquoted forms behave alike for REST sources that stringify numbers; and a JSON boolean throws here but yields 1 in Newtonsoft, because silently turning true into a number hides a real data bug.

Writing is byte-identical to the built-in converter.

Properties​

HandleNull​

public bool HandleNull { get; }

Property Value​

Boolean

Type​

public Type Type { get; }

Property Value​

Type

Constructors​

NewtonsoftParityInt32Converter()​

public NewtonsoftParityInt32Converter()

Methods​

Read(out Utf8JsonReader, Type, JsonSerializerOptions)​

public int Read(out Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

Parameters​

reader Utf8JsonReader

typeToConvert Type

options JsonSerializerOptions

Returns​

Int32

Write(Utf8JsonWriter, Int32, JsonSerializerOptions)​

public void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)

Parameters​

writer Utf8JsonWriter

value Int32

options JsonSerializerOptions

ReadAsPropertyName(out Utf8JsonReader, Type, JsonSerializerOptions)​

public int ReadAsPropertyName(out Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

Parameters​

reader Utf8JsonReader

typeToConvert Type

options JsonSerializerOptions

Returns​

Int32

WriteAsPropertyName(Utf8JsonWriter, Int32, JsonSerializerOptions)​

public void WriteAsPropertyName(Utf8JsonWriter writer, int value, JsonSerializerOptions options)

Parameters​

writer Utf8JsonWriter

value Int32

options JsonSerializerOptions