枚举报错 No enum constant XX 处理方法

2年前 (2022) 程序员胖胖胖虎阿
357 0 0

解决过程:

  1. 一开始以为是项目没有 Install ,尝试 mvn clean install 后仍未解决。
  2. 尝试断点调试 service 层,但调试始终不进入 service 便直接报错。
  3. 断点调试 controller 层,可以进入调试 ,但 F5进入 service.xxx 方法则直接报错
  4. 再次查看代码,发现 mybatis resultType 直接指定实体类对象,中间涉及 数据库类型 转换为 枚举类型
  5. mybatis 默认使用转换器EnumTypeHandler 进行转换,类型为字符串。

解决方法:

修改 mybatis xml文件,将 resultType 修改为 resultMap配置,根据字段需要指定转换类为EnumOrdinalTypeHandler (前提条件为 enum 中下标key必须从0开始,且数据库与之对应,否则则会出现数组越界错误 由此可见,此类型处理器适用性不广,建议自己重写一个通用的 int to enum EnumIntegerTypeHandler)

示例如下:

<resultMap id="queryXXXResultMap" type="com.test.bean.XXX">
  <result column="columnName" property="propertyName"
    typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
</resultMap>

<select id="queryXXX" resultMap="queryXXXResultMap">
  select
    id,
    name
  from
    xxx_table
</select>

补充:

如果本身就是 resultMap 配置了多个字段,只涉及其中个别字段需要 枚举转换则 只需要在对应列上 添加 typeHandler 属性

以上方法前提条件为 enum 中下标key必须从0开始,且数据库与之对应,否则则会出现数组越界错误 由此可见,此类型处理器适用性不广,建议自己重写一个通用的 int to enum EnumIntegerTypeHandler

自定义整型转换为枚举类型处理器:

1. 定义获取枚举整型key接口

/**
 * 获取枚举整型key接口 在需要使用 EnumIntegerTypeHandler 类型处理器的 enum 上 implements EnumIntegerKeyInterface 类
 * 并实现其方法 示例:com.huayizhe.pojo.eu.ItemCommentLevelEnum
 *
 * @author HuaYiZhe
 * @date 2022/3/18 1:10
 * @since v1.0.0
 */
public interface EnumIntegerKeyInterface {

  /**
   * 获取枚举 key
   *
   * @return 枚举的 key
   */
  Integer getEnumIntegerKey();
}

2. 整型转换为枚举类型处理器

/**
 * 自定义整型转换为枚举类型处理器 在需要使用该类型处理器的 enum 上 implements EnumIntegerKeyInterface 类 并实现其方法
 * 示例:com.huayizhe.pojo.eu.ItemCommentLevelEnum
 *
 * @author HuaYiZhe
 * @date 2022/3/18 1:12
 * @since v1.0.0
 */
public class EnumIntegerTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {

  /** 枚举类型 */
  private final Class<E> type;

  /** 使用 map 类型代替 EnumOrdinalTypeHandler 中 E[] enums 枚举数组, 解决 enum key 未从0开始的问题 */
  private final Map<Integer, E> enumMap = new HashMap<>();

  public EnumIntegerTypeHandler(Class<E> type) {
    if (type == null) {
      throw new IllegalArgumentException("Type argument cannot be null");
    }

    // 初始化枚举类型
    this.type = type;
    // 按顺序获取枚举类型
    E[] enums = type.getEnumConstants();
    if (enums == null) {
      throw new IllegalArgumentException(
          type.getSimpleName() + " does not represent an enum type.");
    }
    // 遍历枚举类型
    for (E e : enums) {
      // 将枚举转换为 EnumIntegerKeyInterface 类型,调用其 getEnumIntegerKey 方法获取枚举 key 作为 enumMap的 key
      EnumIntegerKeyInterface enumIntegerKeyInterface = (EnumIntegerKeyInterface) e;
      this.enumMap.put(enumIntegerKeyInterface.getEnumIntegerKey(), e);
    }
  }

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType)
      throws SQLException {
    // 将枚举转换为 EnumIntegerKeyInterface 类型 并设置参数
    EnumIntegerKeyInterface enumIntegerKeyInterface = (EnumIntegerKeyInterface) parameter;
    ps.setInt(i, enumIntegerKeyInterface.getEnumIntegerKey());
  }

  @Override
  public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
    int key = rs.getInt(columnName);
    if (key == 0 && rs.wasNull()) {
      return null;
    }
    return getIntegerEnum(key);
  }

  @Override
  public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    int key = rs.getInt(columnIndex);
    if (key == 0 && rs.wasNull()) {
      return null;
    }
    return getIntegerEnum(key);
  }

  @Override
  public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    int key = cs.getInt(columnIndex);
    if (key == 0 && cs.wasNull()) {
      return null;
    }
    return getIntegerEnum(key);
  }

  /**
   * @param key 数据库值 对应的枚举 key
   * @return 对应的枚举类型
   */
  private E getIntegerEnum(int key) {
    try {
      return this.enumMap.get(key);
    } catch (Exception ex) {
      throw new IllegalArgumentException(
          "Cannot convert " + key + " to " + type.getSimpleName() + " by value.", ex);
    }
  }
}
/**
 * 商品评论等级枚举
 *
 * @author HuaYiZhe
 * @date 2021/4/5 17:06
 * @since v1.0.0
 */
public enum ItemCommentLevelEnum implements EnumIntegerKeyInterface {
  GOOD(1, "好评"),
  NORMAL(2, "中评"),
  BAD(3, "差评");

  public final Integer key;
  public final String value;

  ItemCommentLevelEnum(Integer key, String value) {
    this.key = key;
    this.value = value;
  }

  @Override
  public Integer getEnumIntegerKey() {
    return this.key;
  }
}

至此,则较为完善的解决了该问题。

版权声明:程序员胖胖胖虎阿 发表于 2022年10月4日 上午6:56。
转载请注明:枚举报错 No enum constant XX 处理方法 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...