Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<FieldLevelConverterWriteData> 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())
Expand Down Expand Up @@ -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<String> {
@Override
public Class<?> supportJavaTypeKey() {
Expand Down
17 changes: 15 additions & 2 deletions website/docs/sheet/advanced/custom-converter.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public class CustomStringStringConverter implements Converter<String> {
### 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

---
Expand All @@ -77,13 +77,26 @@ public class CustomStringStringConverter implements Converter<String> {

### 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());
}
Expand Down
17 changes: 15 additions & 2 deletions website/docs/sheet/write/converter.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,27 @@ 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
@Test
public void globalConverterWrite() {
String fileName = "globalConverterWrite" + System.currentTimeMillis() + ".xlsx";
FesodSheet.write(fileName, DemoData.class)
.registerConverter(new CustomStringStringConverter())
.registerConverter(new GlobalStringWriteConverter())
.sheet()
.doWrite(data());
}
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public class CustomStringStringConverter implements Converter<String> {
### 转换器解析优先级

1. 字段级转换器(`@ExcelProperty(converter = ...)`)— 最高优先级
2. 构建器级转换器(`.registerConverter(...)`)
2. 查找键匹配的构建器级转换器(`.registerConverter(...)`)
3. 内置默认转换器 — 最低优先级

---
Expand All @@ -77,13 +77,26 @@ public class CustomStringStringConverter implements Converter<String> {

### 使用全局转换器写入

普通 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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,27 @@ 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
@Test
public void globalConverterWrite() {
String fileName = "globalConverterWrite" + System.currentTimeMillis() + ".xlsx";
FesodSheet.write(fileName, DemoData.class)
.registerConverter(new CustomStringStringConverter())
.registerConverter(new GlobalStringWriteConverter())
.sheet()
.doWrite(data());
}
Expand All @@ -120,5 +133,5 @@ public void globalConverterWrite() {
当多个转换器可能应用于某个字段时,Fesod 按以下顺序进行解析:

1. 字段级转换器(`@ExcelProperty(converter = ...)`)— 最高优先级
2. 构建器级转换器(`.registerConverter(...)`)
2. 查找键匹配的构建器级转换器(`.registerConverter(...)`)
3. 内置默认转换器 — 最低优先级
Loading