You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用RSQL查询枚举类型触发InvalidDataAccessApiUsageException问题

解决RSQL查询枚举类型属性时的类型不匹配异常

这个问题我之前也碰到过——本质是RSQL解析出来的字符串参数直接传给JPA后,JPA没办法自动把字符串转换成你的SiteType枚举类型,所以才会抛出InvalidDataAccessApiUsageException。

问题原因

你的Site实体中siteType字段是SiteType枚举,虽然用@Enumerated(EnumType.STRING)指定了数据库存储为字符串,但RSQL解析查询语句时,会把LOCAL当成普通字符串参数传递,而JPA的Specification在构建查询条件时,无法自动完成字符串到枚举的类型转换,导致类型不匹配。

解决方案:修改CustomRsqlVisitor,添加枚举类型转换逻辑

你需要在自定义的CustomRsqlVisitor中,处理每个比较节点(比如EQ、IN)时,判断目标属性是否为枚举类型,如果是,就把字符串参数转换成对应的枚举实例。

1. 处理EqualsNode(==操作)

修改visit(EqualsNode)方法,添加枚举转换逻辑:

@Override
public Specification<Site> visit(EqualsNode node) {
    String property = node.getSelector();
    List<String> arguments = node.getArguments();
    return (root, query, cb) -> {
        // 获取当前属性的Java类型
        Class<?> propertyType = root.get(property).getJavaType();
        Object value = arguments.get(0);
        
        // 如果是枚举类型,将字符串转为枚举实例
        if (Enum.class.isAssignableFrom(propertyType)) {
            // 可选:统一大小写,避免因大小写不一致报错
            String enumValue = arguments.get(0).toUpperCase();
            value = Enum.valueOf((Class<? extends Enum>) propertyType, enumValue);
        }
        
        return cb.equal(root.get(property), value);
    };
}

2. 处理InNode(in操作)

如果你的查询用到了in操作(比如siteType=in=(LOCAL,ONDEMAND)),同样需要修改visit(InNode)方法:

@Override
public Specification<Site> visit(InNode node) {
    String property = node.getSelector();
    List<String> arguments = node.getArguments();
    return (root, query, cb) -> {
        Class<?> propertyType = root.get(property).getJavaType();
        List<Object> convertedValues = new ArrayList<>();
        
        if (Enum.class.isAssignableFrom(propertyType)) {
            Class<? extends Enum> enumType = (Class<? extends Enum>) propertyType;
            for (String arg : arguments) {
                // 统一大小写后转换为枚举
                convertedValues.add(Enum.valueOf(enumType, arg.toUpperCase()));
            }
        } else {
            convertedValues.addAll(arguments);
        }
        
        return root.get(property).in(convertedValues);
    };
}

3. 其他比较节点的处理

类似的,对于NotEqualsNode(!=)、GreaterThanNode等其他节点,只要涉及到枚举属性的参数传递,都需要做同样的类型转换处理,确保字符串参数被正确转为枚举实例。

额外注意事项

  • 枚举值大小写:如果你的RSQL查询可能传入小写或混合大小写的枚举值,一定要加上toUpperCase()(或toLowerCase(),根据你的枚举定义调整),避免Enum.valueOf抛出IllegalArgumentException。
  • 枚举合法性:可以额外添加校验逻辑,判断传入的字符串是否是有效的枚举值,比如用Arrays.stream(enumType.getValues()).anyMatch(e -> e.name().equalsIgnoreCase(arg)),如果无效可以提前抛出友好的异常。

内容的提问来源于stack exchange,提问作者Rajesh Jaiswal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:33:54