Table of Contents

Bodu.Financial.Serialization.Json Namespace

Bodu.Financial.Serialization.Json

Bodu.Financial.Serialization.Json

Purpose

Bodu.Financial.Serialization.Json carries the System.Text.Json integration for Bodu.Financial. It supplies the six converters that round-trip Money, Money<TCurrency>, CalculatedMoney, MoneyBag, ExchangeRate, and CurrencyPair to and from JSON, together with a one-call extension that registers them under a chosen policy and a dependency-injection registration for containers.

The core Bodu.Financial library is serialization-agnostic - its monetary types carry no [JsonConverter] attribute. Add this package and call AddFinancialJsonConverters to opt into JSON support and select a wire policy across a whole JsonSerializerOptions instance.

Static documentation

Key types

Wire shapes

Policy Money<TCurrency> / Money MoneyBag Use when
Strict (default) { "amount": 19.99, "currency": "USD" } { "balances": { "USD": 100.00, "EUR": 50.00 } } Storing canonical ledger payloads. Validates currency match, rejects duplicate keys.
Lenient Same as Strict Same as Strict Importing third-party data. Normalises lowercase ISO codes, trims whitespace before validation.
Compact "19.99 USD" { "USD": 100.00, "EUR": 50.00 } Log lines, API payloads where verbosity matters. Accepts either "19.99 USD" or "USD 19.99" on read.

Example

using System.Text.Json;
using Bodu.Financial;
using Bodu.Financial.Currencies;
using Bodu.Financial.Serialization.Json;

// Registration is required - the core types carry no [JsonConverter] attribute.
var strict = new JsonSerializerOptions().AddFinancialJsonConverters();

string ledger = JsonSerializer.Serialize(new Money<USD>(19.99m), strict);
// { "amount": 19.99, "currency": "USD" }

// Compact for log lines.
var options = new JsonSerializerOptions()
    .AddFinancialJsonConverters(FinancialJsonPolicy.Compact);

string compact = JsonSerializer.Serialize(new Money<USD>(19.99m), options);
// "19.99 USD"

// Lenient for ingest workflows.
var lenient = new JsonSerializerOptions()
    .AddFinancialJsonConverters(FinancialJsonPolicy.Lenient);

Money<USD> imported = JsonSerializer.Deserialize<Money<USD>>(
    "{ \"amount\": 19.99, \"currency\": \"usd\" }", lenient)!;

Notes

  • Registration is required. The core monetary types carry no [JsonConverter] attribute, so JSON support is opt-in: call AddFinancialJsonConverters (or add converters to JsonSerializerOptions.Converters) before serializing. Without registration, JsonSerializer silently falls back to reflection-shaped output rather than throwing.
  • Currency-mismatch on Money<TCurrency>. Strict and Lenient policies both reject payloads whose "currency" field does not match TCurrency.IsoCode - drift surfaces as JsonException rather than a silently re-interpreted amount. Money accepts any ISO code and rounds to the registry's MinorUnits for that code.
  • MoneyBag pruning. Zero balances are pruned on round-trip - the deserialised bag matches the canonical form, not the verbatim wire shape.
  • Strict vs. Lenient on Compact. The compact policy accepts both "19.99 USD" and "USD 19.99" regardless of Strict / Lenient because there is no ambiguity to be strict about; lenient and strict behave identically under Compact.
  • AddFinancialJsonConverters. Registers every converter on the same JsonSerializerOptions instance under a single policy. Call this once per options instance; mixing policies across types is not supported.
  • See also: the Bodu.Financial reference, the Money<TCurrency> guide.

Classes

CalculatedMoneyJsonConverter

Converts a CalculatedMoney to and from JSON using the policy supplied at construction. Because CalculatedMoney is the unrounded, deferred-arithmetic tier, its full decimal precision - including trailing zeros - is written verbatim and read back unchanged, so a high-precision unit price survives a round-trip without settling to the currency's minor units.

CurrencyPairJsonConverter

Converts an CurrencyPair to and from JSON using the policy supplied at construction.

ExchangeRateJsonConverter

Converts an ExchangeRate observation to and from JSON using the policy supplied at construction.

FinancialJsonSerializerOptionsExtensions

Extension methods that register the Bodu.Financial JSON converters on a JsonSerializerOptions, picking a coherent shape for every shipped monetary type from a single FinancialJsonPolicy value.

FinancialJsonServiceCollectionExtensions

Provides the dependency-injection registration surface for the financial JsonSerializerOptions.

MoneyBagJsonConverter

Converts a MoneyBag to and from JSON using the policy supplied at construction.

MoneyJsonConverter

Converts a Money to and from JSON using the policy supplied at construction. Mirrors the shape vocabulary of MoneyOfTCurrencyJsonConverter<TCurrency> so a single FinancialJsonPolicy selection produces a coherent on-the-wire format across the monetary types.

MoneyOfTCurrencyJsonConverterFactory

Creates MoneyOfTCurrencyJsonConverter<TCurrency> instances for closed Money<TCurrency> types, applying a configurable FinancialJsonPolicy to every closed converter the factory produces.

MoneyOfTCurrencyJsonConverter<TCurrency>

Converts a Money<TCurrency> to and from JSON using the policy supplied at construction.

Enums

FinancialJsonPolicy

Selects the JSON serialization shape and parsing strictness applied by the Bodu.Financial JSON converters.