Skip to main content

JsonScalar

Namespace: Meshmakers.Octo.Runtime.Contracts.Serialization

Converts a scalar JSON value to its Newtonsoft-parity CLR boxing — the single source of the rules previously hand-rolled across many pipeline nodes and inside RtAttributesConverter. Integers that fit in Int32 box to Int32, larger integers to Int64, reals to Double, ISO-8601 strings to DateTime (when requested), bools to Boolean; objects/arrays return null (callers navigate those structurally).

public static class JsonScalar

Inheritance ObjectJsonScalar

Remarks:

The boxing rules are verified empirically against Newtonsoft by Sdk.Common.PipelineParityTests.AttributeRoundTripClrTypeParityTests. That suite is the authoritative contract — any divergence between these rules and what Newtonsoft's JObject.FromObject / JToken.ToObject in-memory round-trip produces is a regression. Irreducible divergences (float vs double, decimal vs double, DateTimeOffset vs DateTime — lost because JSON has no source-CLR-type marker for those) are listed in AttributeValueParityCorpus.IrreducibleDivergences.

Methods

ToClr(JsonElement, Boolean)

Newtonsoft-parity scalar boxing of .

public static object ToClr(JsonElement element, bool parseDateStrings)

Parameters

element JsonElement

parseDateStrings Boolean

Returns

Object

ToClr(JsonValue, Boolean)

Newtonsoft-parity scalar boxing of a .

public static object ToClr(JsonValue value, bool parseDateStrings)

Parameters

value JsonValue

parseDateStrings Boolean

Returns

Object

Remarks:

A is either element-backed (parsed JSON / Deserialize<JsonNode> / SerializeToNode of a boxed primitive) or CLR-backed (JsonValue.Create(primitive) and its DeepClone — what pipeline nodes produce when they author a scalar, e.g. TransformStringNode's Set(path, JsonValue.Create(result)), surviving the overlay store and detach). Only the element-backed form can be read via GetValue<JsonElement>(); a CLR-backed value throws InvalidOperationException there. So element-backed values route through the proven JsonScalar.ToClr(JsonElement, Boolean), and CLR-backed values are unwrapped by kind with the SAME Newtonsoft-parity boxing (string→string, ISO-string→DateTime, Int32 then Int64 then Double, bool→bool). The Number arm tries Int32 before Int64 before Double because STJ's TryGetValue<T> on a CLR-backed value is exact-type (no numeric coercion): a boxed double 2.0 fails TryGetValue<int> and stays a Double rather than collapsing to Int32 (the Int32-vs-double regression the parity converters guard against).

TryToNumber<T>(JsonNode, out T)

public static bool TryToNumber<T>(JsonNode node, out T value)

Type Parameters

T

Parameters

node JsonNode

value T

Returns

Boolean

TryToDouble(JsonNode, out Double)

Reads as a Double — the non-generic counterpart of TryToNumber<T>. Accepts JSON numbers natively and parses numeric JSON strings under invariant culture; returns false otherwise. Unlike the generic overload (which needs IParsable<T>, net7+), this is available on every target framework — including netstandard2.0 — so callers that cannot use the generic still get the shared parity rules.

public static bool TryToDouble(JsonNode node, out Double value)

Parameters

node JsonNode

value Double

Returns

Boolean