fix: honor wildcard-key custom converters when writing CSV (#1045) (#1056) - #1069
fix: honor wildcard-key custom converters when writing CSV (#1045) (#1056)#1069Mikkey-f wants to merge 1 commit into
Conversation
2b5190f to
68b4bb3
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The current wildcard registration logic can overwrite explicitly-registered (JavaType, STRING) converters depending on registration order, and one new test reads the “workbook” converter map via currentWriteHolder() which may not actually be the workbook holder after a write.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR fixes a long-standing inconsistency where custom write converters registered with a wildcard excel-type key (supportExcelTypeKey() == null) were applied for XLSX writes but silently ignored for CSV writes (which force converter lookup under (JavaType, STRING)). The approach is to duplicate wildcard registrations under the CSV lookup key without changing the converter resolution logic.
Changes:
- Register wildcard-key custom converters under both
(JavaType, null)and(JavaType, STRING)during write-holder initialization. - Add a new regression test suite covering wildcard vs explicit converter behavior across XLSX/CSV and across workbook/sheet holder registration paths.
- Document the
supportExcelTypeKey() == nullwildcard semantics in both EN and zh-cn docs and in theConverterjavadoc.
File summaries
| File | Description |
|---|---|
fesod-sheet/src/main/java/org/apache/fesod/sheet/write/metadata/holder/AbstractWriteHolder.java |
Adds helper-based converter registration and duplicates wildcard registrations for CSV compatibility. |
fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/Converter.java |
Expands javadoc to document wildcard semantics and CSV behavior. |
fesod-sheet/src/test/java/org/apache/fesod/sheet/converter/WildcardConverterWriteTest.java |
Adds regression tests for wildcard converter application and registration in holder maps. |
website/docs/sheet/write/converter.md |
Documents wildcard-key behavior (EN). |
website/i18n/zh-cn/docusaurus-plugin-content-docs/current/sheet/write/converter.md |
Documents wildcard-key behavior (zh-cn). |
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| private void putCustomConverter(Converter<?> converter) { | ||
| getConverterMap() | ||
| .put( | ||
| ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), | ||
| converter); | ||
| if (converter.supportExcelTypeKey() == null) { | ||
| getConverterMap() | ||
| .put( | ||
| ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), CellDataTypeEnum.STRING), | ||
| converter); | ||
| } | ||
| } |
There was a problem hiding this comment.
Addressed: the (JavaType, STRING) registration now only replaces the occupant while it is still the built-in default converter (identity-checked against DefaultConverterLoader.loadDefaultWriteConverter()), so an explicitly registered converter is never displaced regardless of registration order; supportExcelTypeKey() is cached in a local. Regression test csvExplicitStringKeyRegisteredBeforeWildcardStillWins covers the order you described.
| Map<ConverterKeyBuild.ConverterKey, Converter<?>> workbookMap = | ||
| excelWriter.writeContext().currentWriteHolder().converterMap(); | ||
| Map<ConverterKeyBuild.ConverterKey, Converter<?>> sheetMap = | ||
| excelWriter.writeContext().writeSheetHolder().converterMap(); | ||
| excelWriter.finish(); |
There was a problem hiding this comment.
Addressed: workbookMap now reads writeWorkbookHolder().converterMap() — after write() the current holder is the sheet holder, so the two maps were aliased. The writer is now closed via try-with-resources.
68b4bb3 to
9f2782d
Compare
What changed
Custom converters registered with
supportExcelTypeKey() == null(the wildcard key(JavaType, null)) are now also registered under(JavaType, STRING). A singleregisterConverter(...)call now works for both xlsx and CSV writes.Why
AbstractExcelWriteExecutor#doConvertresolves converters with the key(JavaType, targetCellDataType). The xlsx write path leaves the target typenull, so a wildcard registration(JavaType, null)is found. The CSV write path forces the target type toSTRING(csv is converted to string by default), so the same registration misses and the built-in string converter silently takes over: no warning is logged and the CSV output silently diverges from the xlsx output of the same code. See #1045 and #1056 (same root cause as EasyExcel#3054).How
AbstractWriteHolderregisters custom converters at two sites (own registration plus replay of workbook-level registrations when a sheet holder is created); both now delegate to a singleputCustomConverterhelper. When the declared excel type key isnull, the converter is additionally registered under(JavaType, STRING)— the key the CSV lookup uses. No lookup code changes; the write path is untouched.Impact
null-key) registrations: CSV now applies the custom converter instead of silently falling back to the built-in string converter — matching the declared wildcard intent (matches all cell data types). The template-fill write path shares the same registry and benefits automatically.@ExcelProperty(converter = ...)) bypass the registry entirely and are unaffected.Documentation
The
nullsemantics ofConverter#supportExcelTypeKey()are now documented on the method (javadoc) and on the website converter page (EN and zh-cn).Tests
New
WildcardConverterWriteTest(5 tests):true/falseinstead of the custom valuestrue/false)STRING-key registration unaffectedRed/green verified: the failing cases were reproduced against the pre-fix code, then turned green by the fix.
Full suite: 921/921 green; spotless and javadoc pass.
Fixes #1045
Fixes #1056