GitHub user MS-Jing created a discussion: 枚举类型字段转换支持

# 希望添加导入导出枚举类支持
我们有时候需要某个字段是枚举类型的,例如数据库存的是1 而真实的含义可能是正常,当我导入导出的时候 需要的是真实的含义。
如果目前我们可以这样来操作:
用户可以自定义一个枚举接口,那么所有的需要导入导出的枚举字段实现该接口
```java
/**
 * @author luojing
 * @since 2026/8/11 10:33
 * The enumeration that implements this interface has the ability to import and 
export enumerations.
 */
public interface IEnum {

    String getLabel();
}

@AllArgsConstructor
@Getter
public enum UserStatus implements IEnum {

    NORMAL(1, "正常"),
    LOCKING(2, "锁定");


    private final Integer value;
    private final String desc;

    @Override
    public String getLabel() {
        return desc;
    }
}
```

再自定一个这个枚举类型的转换器
```java
package cn.idev.excel.converters.enums;

import cn.idev.excel.converters.Converter;
import cn.idev.excel.enums.CellDataTypeEnum;
import cn.idev.excel.enums.IEnum;
import cn.idev.excel.metadata.GlobalConfiguration;
import cn.idev.excel.metadata.data.ReadCellData;
import cn.idev.excel.metadata.data.WriteCellData;
import cn.idev.excel.metadata.property.ExcelContentProperty;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author luojing
 * @description: enum converter
 * @since 2026/8/11 10:36
 */
public class IEnumConverter implements Converter<IEnum> {

    private static final Map<Class<?>, List<IEnum>> enumCache = new HashMap<>();

    @Override
    public Class<?> supportJavaTypeKey() {
        return IEnum.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    @Override
    public WriteCellData<?> convertToExcelData(IEnum value, 
ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) 
throws Exception {
        if (value != null) {
            return new WriteCellData<>(value.getLabel());
        }
        return new WriteCellData<>();
    }

    @Override
    public IEnum convertToJavaData(ReadCellData<?> cellData, 
ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) 
throws Exception {
        Class<?> type = contentProperty.getField().getType();
        if (!enumCache.containsKey(type)) {
            Object[] enumConstants = type.getEnumConstants();
            List<IEnum> iEnumList = 
Arrays.stream(enumConstants).map(enumConstant -> (IEnum) 
enumConstant).collect(Collectors.toList());
            enumCache.put(type, iEnumList);
        }
        List<IEnum> iEnumList = enumCache.getOrDefault(type, 
Collections.emptyList());
        for (IEnum iEnum : iEnumList) {
            if (iEnum.getLabel().equals(cellData.getStringValue())) {
                return iEnum;
            }
        }
        return null;
    }
}
```

最后在我们需要导出的时候,将导出的类字段上指名这个转换器
```java
@Data
public static class UserInfo {
    /**
     * 用户名
     */
    @ExcelProperty("用户名")
    private String userName;

    /**
     * 用户状态  这里指名用IEnumConverter的转换器
     */
    @ExcelProperty(value = "用户状态", converter = IEnumConverter.class)
    private UserStatus userStatus;
}
```
这样在我们导出的时候就可以直接用了
```java
    @Test
    public void testIEnumConverter() {
        String fileName = System.getProperty("user.dir") + "/iEnumConverter" + 
System.currentTimeMillis() + ".xlsx";

        // 写出枚举类型字段
        FastExcel.write(fileName)
            .head(UserInfo.class)
//            .registerConverter(new IEnumConverter())
            .sheet()
            .doWrite(testDataList());

        // 读取枚举类型字段
        List<UserInfo> list = FastExcel.read(fileName)
//            .registerConverter(new IEnumConverter())
            .head(UserInfo.class)
            .sheet()
            .doReadSync();
        System.out.println(list);
    }
```

# 但是
这并不通用,这意味着我每个枚举字段都需要指名`@ExcelProperty(converter = IEnumConverter.class)` 
或者手动注册转换器`registerConverter(new IEnumConverter())`
而且我看了`CustomSheetWriteHandler` 如果我们可以新增这个特性,那么我们可以对枚举类型的字段导入导出做一个下拉框限制:

# 解决方案(需要提pr)
+ 修改`ConverterKeyBuild#buildKey`方法,让枚举字段可以映射到转换器:
```java
public static ConverterKey buildKey(Class<?> clazz, CellDataTypeEnum 
cellDataTypeEnum) {
    Class<?> boxingClass = BOXING_MAP.get(clazz);
    if (boxingClass != null) {
        return new ConverterKey(boxingClass, cellDataTypeEnum);
    }
    if (clazz == IEnum.class || (clazz.isEnum() && 
IEnum.class.isAssignableFrom(clazz))) {
        // clazz equals IEnum.class or clazz is enum and IEnum is assignable 
from clazz
        return new ConverterKey(IEnum.class, cellDataTypeEnum);
    }
    return new ConverterKey(clazz, cellDataTypeEnum);
}
```
+ 将`IEnumConverter` 注册到`DefaultConverterLoader`中
+ 再次启动,无需每个枚举字段指名转换器和无需手动注册枚举转换器
```java
  @Test
  public void testIEnumConverter() {
      String fileName = System.getProperty("user.dir") + "/iEnumConverter.xlsx";

      // 写出枚举类型字段
      FastExcel.write(fileName)
          .head(UserInfo.class)
          .sheet()
          .doWrite(testDataList());

      // 读取枚举类型字段
      List<UserInfo> list = FastExcel.read(fileName)
          .head(UserInfo.class)
          .sheet()
          .doReadSync();
      System.out.println(list);
  }
```

GitHub link: https://github.com/apache/fesod/discussions/1005

----
This is an automatically sent email for [email protected].
To unsubscribe, please send an email to: [email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to