📋 Product Owner view
Feature inventory, spec alignment, behavioural gaps · Product Owner, Product Manager
⚡ Agent trace · 13 steps · $0.0756 · click to expand
search_claims(query='feature capability user', category='any') →
search_claims(query='api endpoint route', category='any') →
search_claims(query='authentication authorization login', category='any') →
search_claims(query='user', category='any') →
search_claims(query='feature', category='any') →
search_claims(query='implement', category='any') →
get_file_claims(file_path='src/main/java/org/joda/money/Money.java') →
get_file_claims(file_path='src/main/java/org/joda/money/BigMoney.java') →
get_file_claims(file_path='src/main/java/org/joda/money/CurrencyUnit.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/MoneyFormatter.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/MoneyFormatterBuilder.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/MoneyAmountStyle.java') →
search_claims(query='README spec documentation', category='any') →
search_claims(query='test', category='any') →
get_file_claims(file_path='src/main/java/org/joda/money/format/AmountPrinterParser.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/MoneyPrinter.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/MoneyParser.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/MoneyPrintContext.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/MoneyParseContext.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/LiteralPrinterParser.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/SignedPrinterParser.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/MultiPrinterParser.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/MoneyFormatException.java') →
get_file_claims(file_path='src/main/java/org/joda/money/format/GroupingStyle.java') →
get_file_claims(file_path='src/main/java/org/joda/money/Ser.java') →
get_file_claims(file_path='src/main/java/org/joda/money/CurrencyUnitDataProvider.java') →
get_file_claims(file_path='src/main/java/org/joda/money/DefaultCurrencyUnitDataProvider.java') →
get_file_claims(file_path='src/test/java/org/joda/money/format/TestMoneyFormatter.java') →
get_file_claims(file_path='src/main/java/org/joda/money/BigMoneyProvider.java') →
get_file_claims(file_path='src/main/java/org/joda/money/IllegalCurrencyException.java') →
get_file_claims(file_path='src/main/java/org/joda/money/CurrencyMismatchException.java') →
get_file_claims(file_path='src/test/java/org/joda/money/TestMoney.java') →
get_file_claims(file_path='src/test/java/org/joda/money/TestCurrencyUnit.java') →
search_claims(query='readme spec doc', category='any') →
get_file_claims(file_path='src/main/java/org/joda/money/format/MoneyFormatterBuilder.java') →
read_source_file(file_path='src/main/java/org/joda/money/Money.java', start_line=226) →
read_source_file(file_path='src/main/java/org/joda/money/BigMoney.java', start_line=247) →
read_source_file(file_path='src/main/java/org/joda/money/format/MoneyFormatterBuilder.java', start_line=85)
Product View: Joda-Money Library
Feature Inventory
| Feature | Status | Confidence | Notes |
|---|---|---|---|
| Monetary Value Representation (Money) | Implemented | High | Fixed-scale money class (scale = currency's decimal places). Final, immutable, thread-safe. Money.java:45-1350 |
| Arbitrary-Precision Money (BigMoney) | Implemented | High | Variable-scale money class. Immutable, thread-safe. BigMoney.java:45-1736 |
| Currency Unit Registry | Implemented | High | ISO-4217 currency codes, numeric codes, decimal places, country mappings. Loaded from CSV data files. CurrencyUnit.java:50-677 |
| Currency Data Provider (Extensible) | Implemented | High | Abstract CurrencyUnitDataProvider allows custom currency registration. Default loads from classpath CSV. CurrencyUnitDataProvider.java:21-58, DefaultCurrencyUnitDataProvider.java:38-118 |
| Currency Lookup (by code, numeric code, locale, country) | Implemented | High | of(String), ofNumericCode(String/int), of(Locale), ofCountry(String). CurrencyUnit.java:415-422 |
| Currency Constants (USD, EUR, JPY, GBP, CHF, AUD, CAD) | Implemented | High | Seven static final constants for major currencies. CurrencyUnit.java:415-422 |
| Money Arithmetic (add, subtract, multiply, divide) | Implemented | High | Full set of operations on both Money and BigMoney. Scale-aware. Money.java:390-395, BigMoney.java:904-910 |
| Money Comparison (compareTo, isEqual, isGreaterThan, isLessThan) | Implemented | High | Comparison ignores scale (like BigDecimal). Throws CurrencyMismatchException if currencies differ. Money.java:1223-1242, BigMoney.java:1608-1615 |
| Currency Conversion | Implemented | High | convertedTo(CurrencyUnit, BigDecimal, RoundingMode) with validation (rejects negative rates, same-currency with non-1 factor). Money.java:1184-1186, BigMoney.java:1516-1530 |
| Money Parsing (from string) | Implemented | High | Money.parse("GBP 2.43") and BigMoney.parse(). Format: CCC amount. Money.java:226-230, BigMoney.java:262-267 |
| Money Formatting (builder pattern) | Implemented | High | MoneyFormatterBuilder with appendAmount(), appendCurrencyCode(), appendLiteral(), etc. MoneyFormatterBuilder.java:399-402 |
| Amount Formatting Styles | Implemented | High | 8 predefined styles (ASCII, localized, grouping variants). Customizable grouping, decimal point, zero character, sign. MoneyAmountStyle.java:50-680 |
| Localized Currency Symbol | Partial | High | Can print localized symbols (e.g., £, $) but cannot parse them — parser is null. MoneyFormatterBuilder.java:143-145 |
| Signed Formatting (positive/zero/negative variants) | Implemented | High | appendSigned() allows different formatters for positive, zero, and negative amounts. MoneyFormatterBuilder.java:190-192 |
| Serialization | Implemented | High | Custom Externalizable implementation with validation on deserialization (rejects tampered data). Ser.java:33-159 |
| Pseudo-Currency Support | Implemented | High | Currencies with decimalPlaces < 0 (e.g., XXX, XFU). isPseudoCurrency() returns true. CurrencyUnit.java:560-562 |
| Custom Currency Registration (programmatic) | Implemented | High | registerCurrency() with force flag to override existing entries. CurrencyUnit.java:275-283 |
| Country-to-Currency Mapping | Implemented | High | ofCountry(String) and registerCountry(). CurrencyUnit.java:299-301 |
| Thread Safety Guarantees | Implemented | High | All core classes are immutable and thread-safe. MoneyPrinter/MoneyParser interfaces require thread-safe implementations. MoneyPrinter.java:35-37, MoneyParser.java:42-44 |
What the Code Does That the Spec Doesn't Mention
Since no formal spec or README was found in the extracted claims, the following are undocumented product decisions discovered in the code:
-
Android workaround for
stripTrailingZeros()bug —BigMoney.of(CurrencyUnit, double)returns zero for a zero double value to avoid a bug instripTrailingZeros()on Android before v30. This is a platform-specific fix with no documentation.BigMoney.java:262-267 -
Money.equals()vscompareTo()inconsistency —equals()considers scale (so "USD 30.00" ≠ "USD 30"), whilecompareTo()ignores scale. This is documented in Javadoc but is a subtle behavioral trap for users.Money.java:1314-1323,Money.java:1223-1226 -
CurrencyMismatchExceptionallows null first currency — The constructor allowsfirstCurrencyto be null but requiressecondCurrencyto be non-null per Javadoc. This asymmetry is undocumented from a product perspective.CurrencyMismatchException.java:42-50 -
GroupingStyle.FULLhas a copy-paste documentation error — The Javadoc forFULLsays "No grouping occurs" (same asNONE), which is clearly wrong. The actual behavior is full grouping.GroupingStyle.java:35-36 -
DefaultCurrencyUnitDataProvidersilently ignores malformed CSV lines — Lines that don't match the expected regex patterns are silently skipped with no warning or error.DefaultCurrencyUnitDataProvider.java:94-104 -
DefaultCurrencyUnitDataProviderJavadoc has a typo in file name — The docstring mentions 'CurencyData.csv' but the code uses 'CurrencyData.csv'.DefaultCurrencyUnitDataProvider.java:28-36 -
MoneyFormatterBuilder.appendCurrencySymbolLocalized()is print-only — The localized currency symbol can be printed but cannot be parsed back. This is documented in the Javadoc but is a significant limitation for round-trip formatting.MoneyFormatterBuilder.java:143-145 -
MoneyFormattercatches and wrapsIOException— Theprint(Appendable, BigMoneyProvider)method catchesIOExceptionand wraps it inMoneyFormatException. TherethrowIOException()method allows callers to recover the originalIOException.MoneyFormatter.java:183-189,MoneyFormatException.java:68-72 -
BigMoneyProviderinterface explicitly warns about mutability — The interface documentation warns that implementations may be mutable and callers should convert toBigMoneyimmediately. This is a design decision that allows flexibility but shifts responsibility to the caller.BigMoneyProvider.java:39-43 -
Moneyconstructor usesAssertionErrorfor validation — The private constructor throwsAssertionError(notIllegalArgumentException) if the underlyingBigMoneyhas the wrong scale. This is an internal guard, not a public API contract.TestMoney.java:791-815
Spec Gaps
No formal specification document (README, spec, or requirements) was found in the extracted claims. However, based on what a reasonable user would expect from a money library:
-
No rounding mode on
Money.of(CurrencyUnit, BigDecimal)— The basic factory method throwsArithmeticExceptionif the amount has more decimal places than the currency supports. Users must explicitly use theof(CurrencyUnit, BigDecimal, RoundingMode)overload to handle rounding. This is a deliberate design choice (fail-fast) but could surprise users.Money.java:226-230 -
Money.total()with empty input throwsIllegalArgumentException— Callingtotal()with an empty array or iterable throws an exception rather than returning zero. This is a design decision that may not match user expectations.Money.java:245-256 -
BigMoney.equals()considers scale — UnlikeBigDecimal, whereequals()considers scale butcompareTo()doesn't,BigMoneyfollows the same pattern. This means "USD 30.00" and "USD 30" are not equal, which could be surprising.BigMoney.java:1695-1705 -
Currency conversion with same currency and non-1 factor throws —
convertedTo()throwsIllegalArgumentExceptionif the target currency is the same as the source and the conversion multiplier is not 1. This prevents accidental no-op conversions but may not be obvious.BigMoney.java:1516-1530 -
No built-in support for currency exchange rate providers — The library provides
convertedTo()but has no mechanism for plugging in exchange rate services. Users must supply the conversion rate themselves.
Open Questions for Engineering
-
What is the intended use case for
BigMoneyProvider? — The interface explicitly warns that implementations may be mutable. Is there a planned mutable money type, or is this just future-proofing? This affects how we document the API to customers. -
Why does
GroupingStyle.FULLhave the wrong Javadoc? — The docstring says "No grouping occurs" which is clearly a copy-paste error fromNONE. This should be fixed in the next release to avoid confusion. -
Is the Android
stripTrailingZeros()workaround still needed? — The workaround targets Android versions before v30. Should we document this or consider it a legacy concern? -
What is the CSV file name discrepancy about? — The Javadoc mentions 'CurencyData.csv' (typo) but the code uses 'CurrencyData.csv'. Is this a documentation bug, or is there a historical reason for the discrepancy?
-
Should
Money.total()with empty input return zero instead of throwing? — This is a common point of friction. Consider whether atotalOrZero()method or a behavioral change would better serve users. -
Is the
equals()vscompareTo()scale behavior intentional forMoney? —Moneydelegates toBigMoneyforequals(), which considers scale. ButMoneyis supposed to always be at currency scale. Can twoMoneyinstances with the same currency and numeric value ever have different scales? If not, the scale concern inequals()is moot forMoneybut still relevant forBigMoney. -
Should we add a
parseCurrencySymbol()capability? — Currently, localized currency symbols can be printed but not parsed. This limits round-trip formatting for internationalized applications. Is this a feature we should prioritize?