Spec: TextField in a numeric column makes the whole contentlet unindexable (#37272) - #37393
Spec: TextField in a numeric column makes the whole contentlet unindexable (#37272)#37393fabrizzio-dotCMS wants to merge 1 commit into
Conversation
…xable (#37272) Issue-resolution spec only (PR 1 of 2). No implementation. loadFields picks the serialization branch by storage column name rather than by the value, so a Text field whose value is a String but whose column is numeric reaches DecimalFormat.format() and throws. The per-field catch logs at WARN and then rethrows, so one bad field discards the whole contentlet. Both defects date to the initial trunk import (2012); the ES->OpenSearch work only made them visible. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude finished @fabrizzio-dotCMS's task in 1m 22s —— View job Spec review — TextField in a numeric column makes the contentlet unindexable (#37272)Reviewed as a spec (PR 1 of 2): right problem, right scope, measurable criteria. I verified the load-bearing code claims against the branch — they hold. Verified against the code
The problem framing, the "not a regression" evidence, and the out-of-scope reasoning (esp. why content-type-save validation is the wrong lever, and the Questions / points to nail down before PR 2
None of these are blocking — the spec is sound and the fix direction is correct. They're the details I'd want resolved in · |
PR 1 of 2 — spec only. Carries
spec.mdand nothing else. Please review it as a spec, not as code: is this the right problem, scoped right, with measurable criteria? Once approved I branch off this branch and open PR 2 with the implementation. No need to wait for this to merge.Refs #37272
TL;DR
What's broken: a Text field whose value is stored as a
Stringbut whose backing column is numeric (integer1) makes the entire contentlet disappear from the index. Silent — the save works, the UI flags nothing, the reindex shows only a failure count.Why:
ESMappingAPIImpl.loadFieldspicks the serialization branch by the storage column name instead of by the value."integer1"starts withinteger, so the String reachesDecimalFormat.format(), which accepts onlyNumberand always throws. The per-fieldcatchthen logs at WARN and rethrows, aborting the whole document.Context worth knowing before reviewing:
TextField.acceptedDataTypes()includesINTEGER/FLOAT, and dotCMS ships content types shaped this way (htmlpageasset.sortOrder,Vanity URL.order). What decides the failure is the Java class of the value, not the modelling.e8ef584ec9— initial trunk import, 2012. The ES→OpenSearch work neither introduced nor worsened it; the bulk refresh just pushed enough documents through the same path to expose it.ESMappingAPIImplis the shared mapper for both engines (OSBulkHelper:250calls the sametoMap), so the fix covers ES and OS at once.Proposed fix
Best-effort conversion at index time. If the value converts, the numeric branch behaves exactly as today. If it does not, emit
0under the numeric key (consistent with the field'slongmapping) with the original text preserved in_dotraw, plus a WARN naming the field and content type. And a failing field no longer kills the document.Out of scope, with the reasoning written down
FieldFactoryImpl:478). Forbidding the combination means removingINTEGERfromTextField.acceptedDataTypes(), which breaks dotCMS's own built-in content types at bootstrap.Field.fieldValue()respectingdataType()— the preventive counterpart, and it would also close theImportStarterUtilroute, but it changes every save of every contentlet in the system. Different blast radius, deserves its own cycle.Identified risk
ImportStarterUtilwrites contentlet JSON verbatim, bypassing the API entirely (:894→toMutableContentlet,:782→ factorysave). Every user-facing path coerces (new editor, legacy editor, Content Import portlet and the new import job all funnel throughsetContentletProperty→integerStrategy), so the starter import is the most plausible provenance of the observed rows — and it explains why the defect cannot be reproduced through the UI. Named as a known gap; not fixed here.What to scrutinise
AC-005.
htmlpageasset.sortOrderhas exactly this field shape, and its zero-padded_dotraw(0000000000000000054.000000000000000000) is what makes lexicographic sorting equal numeric sorting for page ordering. That document must stay byte-identical. A type-based rule instead of a value-based one would have broken page ordering on every installation — that trade-off is recorded under Resolved Decisions → C-1.🤖 Generated with Claude Code