当前使用版本(必填,否则不予处理)

<mybatis-plus.version>3.3.2</mybatis-plus.version>
在最新的3.4.2版本也测试过了,问题一致

该问题是如何引起的?(确定最新版也有问题再提!!!)

片段一-没问题的版本:

@AllArgsConstructor
@Getter
public enum Level {
    ROOT("根目录", "0", 0),
    FIRST("一级", "1", 1),
    SECOND("二级", "2", 2),
    THIRD("三级", "3", 3);
    private String name;
    private String codeStr;
    @EnumValue
    private Integer code;
}

片段二-添加抽象方法,@EnumValue不生效

@AllArgsConstructor
@Getter
public enum Level {
    ROOT("根目录", "0", 0){
        @Override
        public Level child() {
            return FIRST;
        }
    },
    FIRST("一级", "1", 1){
        @Override
        public Level child() {
            return SECOND;
        }
    },
    SECOND("二级", "2", 2){
        @Override
        public Level child() {
            return THIRD;
        }
    },
    THIRD("三级", "3", 3) {
        @Override
        public Level child() {
            return null;
        }
    };
    private String name;
    private String codeStr;
    public abstract Level child();
    @EnumValue
    private Integer code;
}

重现步骤(如果有就写完整)

1.片段一未添加过抽象方法的实现,使用情况正常 2.片段二为每个枚举类添加抽象方法实现,发现注解@EnumValue不生效

报错信息

sql查询类型错误,没有走code这个Integer值

Comment From: plusmancn

@yoko-murasame 代码片段建议使用 markdown code block 描述,这会让问题表述更加整洁清晰

Comment From: plusmancn

@yoko-murasame 3.4.2 下无法复现你的问题

Comment From: yoko-murasame

@yoko-murasame 3.4.2 下无法复现你的问题 1

感谢帮助,我用的数据库是pgsql13,这个也许是数据库问题?

Comment From: plusmancn

可以断点调试下 com/baomidou/mybatisplus/core/handlers/MybatisEnumTypeHandler.java#getNullableResult 方法看下,光看 valueOf 方法,和数据库关系不大。

Comment From: yoko-murasame

可以断点调试下 com/baomidou/mybatisplus/core/handlers/MybatisEnumTypeHandler.java#getNullableResult 方法看下,光看 valueOf 方法,和数据库关系不大。

我今天新建了个demo,测试了下3.4.2版本,数据库pgsql13,也没发现问题,目前来看是原先项目中其他框架引起的(推测是druid 1.1.21 的影响),最后非常感谢您的帮助!

Comment From: octyu

同遇到了这个问题,在枚举类的抽象方法中去进行数据库操作 @EnumValue 就会失效,否则是正常的。

Comment From: ya0yy

不是抽象方法导致的,是枚举的实现体导致的。

@Getter
@RequiredArgsConstructor
enum PayMethodEnum {

    ALIPAY(1), WECHAT_PAY(2), OTHER(3);

    @EnumValue
    private final int code;
}

以上例子中,枚举成员ALIPAY、WECHAT_PAY、OTHER都属于PayMethodEnum类型,即这三者getClass()的结果都是PayMethodEnum.class

@Getter
@RequiredArgsConstructor
enum PayMethodEnum {

    ALIPAY(1) {
        @Override
        public String toString() {
            return getCode() + "";
        }
    }, 
    WECHAT_PAY(2) {

    },
    OTHER(3);

    @EnumValue
    private final int code;
}

上面这个版本中成员ALIPAY重写了toString方法,而WECHAT_PAY只有一对大括号什么方法都没有实现,此时ALIPAY、WECHAT_PAY虽然也都属于PayMethodEnum类型,但实际上getClass()的结果是PayMethodEnum$序号,这里的'序号'是个变量,根据java编译匿名内部类的规则,会依次在当前类名的名字后面拼接'序号'来当作匿名内部类的类名。所以ALIPAY调用getClass()的结果是PayMethodEnum$1.class,WECHAT_PAY是PayMethodEnum$2.class。而mybatis底层的机制是调用传入的参数对象的getClass根据该对象的所属class去获取handlerType,而mybatis-plus帮我们注册的处理枚举类型的handlerType(类型是MybatisHandlerType)映射的是PayMethodEnum.class,所以此时通过PayMethodEnum$1.class去获取handlerType是拿不到的,最终会走到mybatis自带的默认的枚举类型处理器(EnumTypeHandler)。

解决方案

我将mybatis的默认设置为mybatis-plus提供的枚举类型处理器解决了该问题

# application.yml配置文件
mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

以上均为鄙人拙见,如有纰漏还请指正