'While fetching data using RSQL for enum type resulting InvalidDataAccessApiUsageException

I have an Entity with attribute type enum. I am trying to run query using RSQL. My query is

siteType==LOCAL

But it is resulting below exception because in query I am passing siteType as String Value but in JPA siteType is enum.

org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [LOCAL] did not match expected type [com.dataservice.api.site.wrapper.SiteType (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [permanent] did not match expected type [com.dataservice.api.site.wrapper.SiteType (n/a)]


@Entity
@Table(name = "SITE")
public class Site {

    @Id
    @Column(name = "ID", updatable = false, nullable = false)
    private Long id;

    @Column(name = "NAME")
    private String name;

    @Column(name = "SITE_TYPE")
    @Enumerated(EnumType.STRING)
    private SiteType siteType;

Enum:

 public enum SiteType {
    LOCAL, ONDEMAND;}

RSQL code :

Node rootSearchNode = new RSQLParser().parse(searchQuery);
    Specification<Site> siteSearchSpec = rootSearchNode.accept(new CustomRsqlVisitor<Site>());
    resultSitesList = siteDataService.getSitesBySearchQuery(siteSearchSpec);


Solution 1:[1]

The problem is it does not know how to map the string representation of the enum to the actual enum type. I faced the same problem and worked around it by changing the Entity as:

@Column(name = "SITE_TYPE")
private String siteType;

public void setSiteType(SiteType siteType) {
    this.siteType = siteType.name();
}

public SiteType getSiteType() {
    return Enum.valueOf(SiteType.class, siteType);
}

Solution 2:[2]

private List<Object> castArguments(Root<T> root) {
List<Object> args = new ArrayList<Object>();
Class<? extends Object> type = root.get(property).getJavaType();

for (String argument : arguments) {
  if (type.equals(Integer.class)) {
    args.add(Integer.parseInt(argument));
  } else if (type.equals(Long.class)) {
    args.add(Long.parseLong(argument));
  } else if (type.equals(SiteType.class)) {
    args.add(SiteType.valueOf(argument));
  } else {
    args.add(argument);
  }
}

return args;
}

Taking the suggestion in the comment. Add another else-if check for your own enum type.

Solution 3:[3]

If you want to use an Enum type in RSQL query, cast Enum argument like below:

private List<Object> castArguments(final Root<T> root) {
    
            final Class<? extends Object> type = root.get(property).getJavaType();
    
            final List<Object> args = arguments.stream().map(arg -> {
                if (type.equals(Integer.class)) {
                    return Integer.parseInt(arg);
                } else if (type.equals(Long.class)) {
                    return Long.parseLong(arg);
                } else if (type.isEnum()) {
                    return Enum.valueOf((Class<? extends Enum>) type, arg);
                } else {
                    return arg;
                }
            }).collect(Collectors.toList());
    
            return args;
        }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Selçuk Cihan
Solution 2 selimssevgi
Solution 3 heelha