3

I have a UserAssignmentRole class like this :

@Data
@Entity
public class UserAssignmentRole {
    ...
    @Enumerated(EnumType.STRING)
    public Role role;
}

And the Role is enum, it looks like this:

public enum Role{
    admin,
    member,
    pending
}

Now when in my repository I try to query to select all with role of admin, it gives me error:

@Query("select uar from UserAssignmentRole uar where uar.role=Role.admin")
public List<UserAssignmentRole> listAdmin(Long userID, Long assignmentID);

How this can be solved?

Error : org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'Role.admin'

Full error : https://pastebin.com/tk9r3wDg

Maifee Ul Asad
  • 3,992
  • 6
  • 38
  • 86
  • 1
    Did you use the fully qualified class to you enum? with package. Or you maybe find an answer here: https://stackoverflow.com/questions/18402988/is-there-a-way-to-use-constants-inside-spring-data-query-annotation-value – lczapski Dec 31 '19 at 11:51
  • Where did you placed enum? Can you try to move enum definition to UserAssignmentRole – lczapski Dec 31 '19 at 12:32

2 Answers2

3

It is a strange but intended behaviour of Hibernate since 5.2.x An enum value is a constant and you're using a non-conventional naming (lowercase)

Take a look at this issue and Vlad Mihalcea's long explanation of the performance penalty.

If you’re using non-conventional Java constants, then you’ll have to set the hibernate.query.conventional_java_constants configuration property to false. This way, Hibernate will fall back to the previous behavior, treating any expression as a possible candidate for a Java constant.

zforgo
  • 2,508
  • 2
  • 14
  • 22
1

You can try not to write this sql by yourself but with repository create code like this:

@Repository
public interface UserAssignmentRolelRepository extends JpaRepository<UserModel, Long>{

    public List<UserAssignmentRole> findByRole(Role role);

}

And then:

@Autowired
UserAssignmentRolelRepository repository ;

public void someMethod(){
   List<UserAssignmentRole> userAssignmentRoles = repository.findByRole(Role.admin);
}

UPDATE 1

As it was point out in this answer: non-conventional naming. You can change labels in your enum to uppercase.

public enum Role{
    Admin,
    Member,
    Pending
}

and then:

@Query("select uar from UserAssignmentRole uar where uar.role=com.example.package.Role.Admin")
public List<UserAssignmentRole> listAdmin(Long userID, Long assignmentID);

UPDATE 2

But if you really want to have lowercase in DB. It requires more code to change. Enum change to:

public enum Role{
    Admin("admin"),
    Member("member"),
    Pending("pending");

    private String name;

    Role(String name) {
        this.name = name;
    }

    public String getName() { return name; }

    public static Role parse(String id) {
        Role role = null; // Default
        for (Role item : Role.values()) {
            if (item.name.equals(id)) {
                role = item;
                break;
            }
        }
        return role;
    }
}

In UserAssignmentRole

//    @Enumerated(EnumType.STRING)
    @Convert(converter = RoleConverter.class)
    private Role role;

And additional class:

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public class RoleConverter implements AttributeConverter<Role, String> {

    @Override
    public String convertToDatabaseColumn(Role role) {
        return role.getName();
    }

    @Override
    public Role convertToEntityAttribute(String dbData) {
        return Role.parse(dbData);
    }
}
lczapski
  • 4,026
  • 3
  • 16
  • 32