You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit fecc13a
Browse filesBrowse the repository at this point in the historyBrowse files
fix(java): an unreadable decimal became 0, and a decimal array vanished
Two defects found by asserting VALUES rather than compilation, both in the shared
JVM metadata module, so Kotlin inherits the fixes.
DataConverter.toBigDecimal swallowed NumberFormatException and returned
BigDecimal.ZERO. That is the one wrong answer available: 0 is a plausible amount,
so unreadable input reached a money field as a real-looking value indistinguishable
from a genuine zero. Every sibling converter — toInt, toLong, toDouble, toFloat —
throws for the same input; decimal was the lone exception, and the quiet one. It
now throws too. Nothing pinned the ZERO behaviour except the hazard note in this
branch's own round-trip test, and there is exactly one caller (MetaField:1215), so
the change is contained. In the lenient extract tier assemble's never-throws guard
turns the throw into a lost component, which yields null — the honest answer, and
what that test asserted before it had to be relaxed.
DataTypes had no DECIMAL_ARRAY. arrayTypeFor(DECIMAL) mapped decimal to ITSELF,
with a comment explaining that arrays-of-decimal "aren't in the metamodel" so the
declaration would "degrade gracefully". It did not degrade gracefully: the loader
accepts field.decimal @isarray, every port generates code for it, the conversion
then failed, and the component came back null with no error. C# populates the same
shape correctly — now pinned BY VALUE, not just by compilation, since a reader that
returned an empty list or rounded through a double would have compiled fine — so
this was a JVM port gap wearing a design position's clothes.
Added DECIMAL_ARRAY plus toBigDecimalArray, element-converting through toBigDecimal
rather than a double: routing a decimal array through doubles would defeat the
entire reason field.decimal exists. The new member takes id 22 rather than a tidy
slot beside DECIMAL=10 because those ids are PERSISTED identifiers — renumbering
the existing members to keep the enum ordered would silently repoint stored data.
Scope deliberately stops at the JVM. That conversion table has no C#, TypeScript or
Python analogue (verified, not assumed): TS binds field.decimal to `string` and has
no DECIMAL coercion kind, Python binds it to Decimal, and neither carries a
per-type array conversion enum. One change, one module, two ports.
Verified: metadata 1622 + render/om 292 pass; ci-local.sh --only java green on
conformance and Testcontainers integration for BOTH java and kotlin. The lane's
single red is the pre-existing SpringPayloadGeneratorTest camelCase failure, which
fails identically on a clean tree (macOS case-insensitive filesystem).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: server/java/codegen-spring/src/test/java/com/metaobjects/generator/spring/GeneratedScalarExtractRoundTripTest.java
+20-20Lines changed: 20 additions & 20 deletions
Original file line number
Diff line number
Diff line change
@@ -150,31 +150,31 @@ public void coercedScalarsCarryTheirValuesAndMalformedOnesBecomeNull() throws Ex
150
150
List<?> counts = (List<?>) get(p, "counts");
151
151
assertEquals("int array is element-typed, not List<String>", List.of(3, 4), counts);
152
152
153
-
// A decimal ARRAY is deliberately NOT a metamodel shape: DataTypes has no
154
-
// DECIMAL_ARRAY ("arrays-of-decimal aren't in the metamodel" — the same position
155
-
// C# records as SP-A "decimal is single-only"), so DataTypes.arrayTypeFor maps
156
-
// field.decimal @isArray to DECIMAL and the assembled value cannot be populated.
157
-
// What matters is the FAILURE MODE: the component is lost, and the rest of the
158
-
// payload still parses. Before the never-throws fix in MetaObjectExtractor.assemble
159
-
// this threw out of the whole extract. It still COMPILES (see
160
-
// GeneratedScalarExtractLockStepTest) — a declared shape must never emit broken code
161
-
// even when the runtime cannot fill it.
162
-
assertNull("decimal array is unsupported by the object model — lost, not fatal",
163
-
get(p, "rates"));
153
+
// A decimal ARRAY now populates, element-typed and precision-exact. It used to be
154
+
// dropped silently: DataTypes had no DECIMAL_ARRAY, so arrayTypeFor(DECIMAL)
155
+
// returned DECIMAL, the conversion failed, and the component came back null with
156
+
// no error — while the loader accepted the declaration and every port generated
157
+
// code for it. C# populated the same shape correctly, so this was a JVM port
158
+
// divergence rather than a metamodel position.
159
+
List<?> rates = (List<?>) get(p, "rates");
160
+
assertNotNull("decimal array must populate", rates);
161
+
assertEquals("rates size", 2, rates.size());
162
+
assertTrue("rates element is BigDecimal, not String", rates.get(0) instanceofBigDecimal);
0 commit comments