bengbengbalabalabeng commented on issue #648:
URL: https://github.com/apache/fesod/issues/648#issuecomment-3468192542
问题触发条件
1. 用户通过 registerConverter() 注册了一个或多个全局自定义的 Converter<?>。
2. 在需要转换的实体类字段上,未使用 @ExcelProperty(converter = ...) 注解显式指定转换器。
3. 写入的目标文件格式不是 CSV (ExcelTypeEnum.CSV)。
初步分析
问题的根源在于 `AbstractExcelWriteExecutor#doConvert` 方法中获取全局转换器的逻辑。
`cn.idev.excel.write.metadata.holder.AbstractWriteHolder`
<details>
<summary>Code</summary>
```java
public AbstractWriteHolder(WriteBasicParameter writeBasicParameter,
AbstractWriteHolder parentAbstractWriteHolder) {
// ......
// Set converterMap
if (parentAbstractWriteHolder == null) {
setConverterMap(DefaultConverterLoader.loadDefaultWriteConverter());
} else {
setConverterMap(new
HashMap<>(parentAbstractWriteHolder.getConverterMap()));
}
if (writeBasicParameter.getCustomConverterList() != null
&& !writeBasicParameter.getCustomConverterList().isEmpty()) {
for (Converter<?> converter :
writeBasicParameter.getCustomConverterList()) {
getConverterMap()
.put(
ConverterKeyBuild.buildKey(
//
[Mark-1]
converter.supportJavaTypeKey(),
converter.supportExcelTypeKey()),
converter);
}
}
}
```
</details>
> Note: [Mark-1]
`cn.idev.excel.write.executor.AbstractExcelWriteExecutor#doConvert`
<details>
<summary>Code</summary>
```java
private WriteCellData<?> doConvert(CellWriteHandlerContext
cellWriteHandlerContext) {
ExcelContentProperty excelContentProperty =
cellWriteHandlerContext.getExcelContentProperty();
Converter<?> converter = null;
// get converter by @ExcelProperty(converter = ...)
if (excelContentProperty != null) {
converter = excelContentProperty.getConverter();
}
// get converter by Converter Map
if (converter == null) {
// csv is converted to string by default
// [Mark-2]
if (writeContext.writeWorkbookHolder().getExcelType() ==
ExcelTypeEnum.CSV) {
cellWriteHandlerContext.setTargetCellDataType(CellDataTypeEnum.STRING);
}
converter = writeContext
.currentWriteHolder()
.converterMap()
.get(ConverterKeyBuild.buildKey(
cellWriteHandlerContext.getOriginalFieldClass(),
// [Mark-3]
cellWriteHandlerContext.getTargetCellDataType()));
}
// ......
if (converter == null) {
throw new ExcelWriteDataConvertException(
cellWriteHandlerContext,
"Can not find 'Converter' support class "
+
cellWriteHandlerContext.getOriginalFieldClass().getSimpleName() + ".");
}
// ......
return cellData;
}
```
</details>
> Note: [Mark-2]、[Mark-3]
在 `ExcelWriteAddExecutor#add` 方法(调用链)中,会先构造一个 `CellWriteHandlerContext`
对象,但此时并没有对 `targetCellDataType` 字段进行赋值。随后调用 `converterAndSet` -> `doConvert`
时,如果 `@ExcelProperty` 注解未显式指定 `converter`,就会进入全局 `Converter<?>`的获取逻辑。
然而,当 [Mark-2] 条件不成立时,[Mark-3] 中的 `TargetCellDataType` 会一直保持为 `NULL`。这会导致通过
[Mark-1] 添加的 `Converter<?>` 无法被正确匹配,从而抛出异常。
讨论
- 是否需要在 [Mark-1] 添加 excelTypeKey(感觉
`CellWriteHandlerContext#targetCellDataType` 类型赋值问题不好解)
- 个人觉得通过 registerConverter() 同时注册多个相同类型的全局 Converter 本身不太合理,应该使用
@ExcelProperty(converter = ...) 显式指定会更好(优先级高)。
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]