diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converter/CustomConverterTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converter/CustomConverterTest.java index f838c7c5f..03ec70f50 100644 --- a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converter/CustomConverterTest.java +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converter/CustomConverterTest.java @@ -38,11 +38,18 @@ import org.apache.fesod.sheet.testkit.Tags; import org.apache.fesod.sheet.testkit.base.AbstractExcelTest; import org.apache.fesod.sheet.testkit.builders.TestDataBuilder; +import org.apache.fesod.sheet.testkit.enums.ExcelFormat; +import org.apache.fesod.sheet.testkit.params.ExcelFormatSource; +import org.apache.fesod.sheet.testkit.params.FormatScope; import org.apache.fesod.sheet.write.builder.ExcelWriterSheetBuilder; import org.apache.fesod.sheet.write.metadata.holder.WriteSheetHolder; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; @Tag(Tags.ROUND_TRIP) public class CustomConverterTest extends AbstractExcelTest { @@ -122,6 +129,28 @@ void fieldLevelConverterTakesPrecedenceOverRegisteredConverter() throws Exceptio Assertions.assertTrue(csvContent.contains("field:value,registered:value")); } + @ParameterizedTest + @ExcelFormatSource(FormatScope.BINARY) + void globalExcelConverterRespectsFieldLevelOverride(ExcelFormat format) throws Exception { + File file = createTempFile(format); + FieldLevelConverterWriteData writeData = new FieldLevelConverterWriteData(); + writeData.setFieldValue("value"); + writeData.setRegisteredValue("value"); + List list = new ArrayList<>(); + list.add(writeData); + + FesodSheet.write(file, FieldLevelConverterWriteData.class) + .registerConverter(new GlobalStringWriteConverter()) + .sheet() + .doWrite(list); + + try (Workbook workbook = WorkbookFactory.create(file)) { + Row row = workbook.getSheetAt(0).getRow(1); + Assertions.assertEquals("field:value", row.getCell(0).getStringCellValue()); + Assertions.assertEquals("registered:value", row.getCell(1).getStringCellValue()); + } + } + private void writeFile(File file) { FesodSheet.write(file) .registerConverter(new TimestampNumberConverter()) @@ -184,6 +213,13 @@ public WriteCellData convertToExcelData( } } + public static class GlobalStringWriteConverter extends RegisteredStringConverter { + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + } + public static class RegisteredStringConverter implements Converter { @Override public Class supportJavaTypeKey() { diff --git a/website/docs/sheet/advanced/custom-converter.md b/website/docs/sheet/advanced/custom-converter.md index 71ce5ed52..699bc9025 100644 --- a/website/docs/sheet/advanced/custom-converter.md +++ b/website/docs/sheet/advanced/custom-converter.md @@ -68,7 +68,7 @@ public class CustomStringStringConverter implements Converter { ### Converter Resolution Priority 1. Field-level converter (`@ExcelProperty(converter = ...)`) — highest priority -2. Builder-level converter (`.registerConverter(...)`) +2. Builder-level converter (`.registerConverter(...)`) with a matching lookup key 3. Built-in default converter — lowest priority --- @@ -77,13 +77,26 @@ public class CustomStringStringConverter implements Converter { ### Write with Global Converter +For ordinary XLSX/XLS writes, global converter lookup uses the Java type and a `null` Excel type key. Use the following variant of the converter above. The returned `WriteCellData` still determines the output cell type; returning `null` here only changes the lookup key. + +```java +public class GlobalStringWriteConverter extends CustomStringStringConverter { + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } +} +``` + +For CSV writing and reading string cells, register the original `CustomStringStringConverter`, which returns `CellDataTypeEnum.STRING`. + ```java @Test public void customConverterWrite() { String fileName = "customConverterWrite" + System.currentTimeMillis() + ".xlsx"; FesodSheet.write(fileName, DemoData.class) - .registerConverter(new CustomStringStringConverter()) + .registerConverter(new GlobalStringWriteConverter()) .sheet() .doWrite(data()); } diff --git a/website/docs/sheet/write/converter.md b/website/docs/sheet/write/converter.md index 3199ec587..11204b0cf 100644 --- a/website/docs/sheet/write/converter.md +++ b/website/docs/sheet/write/converter.md @@ -100,6 +100,19 @@ public void converterWrite() { Register a converter at the builder level to apply it to ALL fields matching the Java type and Excel type. This is useful when you want the same transformation applied globally without annotating each field. +For ordinary XLSX/XLS writes, global converter lookup uses the Java type and a `null` Excel type key. Use the following variant of the converter above. The returned `WriteCellData` still determines the output cell type; returning `null` here only changes the lookup key. + +```java +public class GlobalStringWriteConverter extends CustomStringStringConverter { + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } +} +``` + +For CSV writing and reading string cells, register the original `CustomStringStringConverter`, which returns `CellDataTypeEnum.STRING`. + ### Code Example ```java @@ -107,7 +120,7 @@ Register a converter at the builder level to apply it to ALL fields matching the public void globalConverterWrite() { String fileName = "globalConverterWrite" + System.currentTimeMillis() + ".xlsx"; FesodSheet.write(fileName, DemoData.class) - .registerConverter(new CustomStringStringConverter()) + .registerConverter(new GlobalStringWriteConverter()) .sheet() .doWrite(data()); } @@ -120,5 +133,5 @@ public void globalConverterWrite() { When multiple converters could apply to a field, Fesod resolves them in this order: 1. Field-level converter (`@ExcelProperty(converter = ...)`) — highest priority -2. Builder-level converter (`.registerConverter(...)`) +2. Builder-level converter (`.registerConverter(...)`) with a matching lookup key 3. Built-in default converter — lowest priority diff --git a/website/i18n/zh-cn/docusaurus-plugin-content-docs/current/sheet/advanced/custom-converter.md b/website/i18n/zh-cn/docusaurus-plugin-content-docs/current/sheet/advanced/custom-converter.md index 0e7eb32b5..abe3247f1 100644 --- a/website/i18n/zh-cn/docusaurus-plugin-content-docs/current/sheet/advanced/custom-converter.md +++ b/website/i18n/zh-cn/docusaurus-plugin-content-docs/current/sheet/advanced/custom-converter.md @@ -68,7 +68,7 @@ public class CustomStringStringConverter implements Converter { ### 转换器解析优先级 1. 字段级转换器(`@ExcelProperty(converter = ...)`)— 最高优先级 -2. 构建器级转换器(`.registerConverter(...)`) +2. 查找键匹配的构建器级转换器(`.registerConverter(...)`) 3. 内置默认转换器 — 最低优先级 --- @@ -77,13 +77,26 @@ public class CustomStringStringConverter implements Converter { ### 使用全局转换器写入 +普通 XLSX/XLS 写入按 Java 类型和 `null` Excel 类型键查找全局转换器,因此需要使用上述转换器的以下变体。输出单元格类型仍由返回的 `WriteCellData` 决定;此处返回 `null` 仅改变查找键。 + +```java +public class GlobalStringWriteConverter extends CustomStringStringConverter { + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } +} +``` + +写入 CSV 或读取字符串单元格时,请注册返回 `CellDataTypeEnum.STRING` 的原始 `CustomStringStringConverter`。 + ```java @Test public void customConverterWrite() { String fileName = "customConverterWrite" + System.currentTimeMillis() + ".xlsx"; FesodSheet.write(fileName, DemoData.class) - .registerConverter(new CustomStringStringConverter()) + .registerConverter(new GlobalStringWriteConverter()) .sheet() .doWrite(data()); } diff --git a/website/i18n/zh-cn/docusaurus-plugin-content-docs/current/sheet/write/converter.md b/website/i18n/zh-cn/docusaurus-plugin-content-docs/current/sheet/write/converter.md index 666d8eb74..146ef552c 100644 --- a/website/i18n/zh-cn/docusaurus-plugin-content-docs/current/sheet/write/converter.md +++ b/website/i18n/zh-cn/docusaurus-plugin-content-docs/current/sheet/write/converter.md @@ -100,6 +100,19 @@ public void converterWrite() { 在构建器级别注册转换器,将其应用于所有匹配 Java 类型和 Excel 类型的字段。当您希望对所有字段统一应用相同的转换逻辑时非常有用,无需逐一注解。 +普通 XLSX/XLS 写入按 Java 类型和 `null` Excel 类型键查找全局转换器,因此需要使用上述转换器的以下变体。输出单元格类型仍由返回的 `WriteCellData` 决定;此处返回 `null` 仅改变查找键。 + +```java +public class GlobalStringWriteConverter extends CustomStringStringConverter { + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } +} +``` + +写入 CSV 或读取字符串单元格时,请注册返回 `CellDataTypeEnum.STRING` 的原始 `CustomStringStringConverter`。 + ### 代码示例 ```java @@ -107,7 +120,7 @@ public void converterWrite() { public void globalConverterWrite() { String fileName = "globalConverterWrite" + System.currentTimeMillis() + ".xlsx"; FesodSheet.write(fileName, DemoData.class) - .registerConverter(new CustomStringStringConverter()) + .registerConverter(new GlobalStringWriteConverter()) .sheet() .doWrite(data()); } @@ -120,5 +133,5 @@ public void globalConverterWrite() { 当多个转换器可能应用于某个字段时,Fesod 按以下顺序进行解析: 1. 字段级转换器(`@ExcelProperty(converter = ...)`)— 最高优先级 -2. 构建器级转换器(`.registerConverter(...)`) +2. 查找键匹配的构建器级转换器(`.registerConverter(...)`) 3. 内置默认转换器 — 最低优先级