Joda Money

What it is

This library provides immutable representations of monetary amounts and currencies. It solves the problem of precisely representing and manipulating money values using arbitrary-precision arithmetic, avoiding floating-point rounding errors, and handling currency-specific validation, formatting, and conversion.

What it does

The core API offers two monetary value types: one using BigDecimal for arbitrary precision and one that enforces a fixed scale based on currency decimal places. It includes a currency registry with predefined currencies and support for custom registration via a provider interface. Formatting and parsing are handled by a builder that composes printers and parsers, supporting localized grouping styles. Arithmetic operations such as addition, subtraction, multiplication, and rounding are provided, with currency matching enforced before calculations. The library also exposes utility methods for comparisons and null-safe checks.

Architecture health

The library has zero import cycles. The zone of pain includes the monetary value class with 11 incoming dependencies, the currency registry with 6, the fixed-scale money type with 3, and the interface it implements with 3. The zone of uselessness consists of five formatting leaf classes. There are 30 files using the Immutable Value Object pattern. Test coverage consists of 15 test files for 24 source files.

What it enforces

Operations between different currencies throw a specific exception when currencies do not match. Factory methods for the fixed-scale money validate that the amount’s scale does not exceed the currency’s decimal places, throwing ArithmeticException if it does. Currency registration validates that codes are exactly three uppercase letters and numeric codes are between -1 and 999, with unique constraints enforced; conflicts raise IllegalArgumentException. Null parameters are rejected with NullPointerException. Custom serialization writes type-specific data for monetary and currency types.

Definition of Done

A monetary value is successfully created from a currency and amount, with scale validation applied for the fixed-scale type. Arithmetic operations proceed only when currency equality is confirmed. Parsing follows the format of a three-letter currency code followed by a numeric amount. Formatting respects locale-specific grouping and decimal symbols, handling negative signs and zero-character substitution. A parse context tracks the current parse index and error state, setting the error index on failure.

Gaps and risks

The zone of pain files are central and changes to them could affect many dependents. There is no evidence of explicit concurrency handling beyond a single cache implementation. Utility methods treat null inputs as zero for some comparisons, potentially masking null-related bugs. The serialization mechanism is custom and may not be compatible with other serialization frameworks. No semgrep findings were reported.