Uploaded image for project: 'Hibernate ORM'
  1. HHH-10282

AttributeConverter for Enum within JPQL query

    Details

    • Type: Improvement
    • Status: Open
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: 5.0.3
    • Fix Version/s: 6.0.0.Alpha2
    • Component/s: None
    • Labels:
      None
    • Environment:
      Ubuntu 12.04 x64 / Spring 4.2 / Hibernate 5.0.3
    • Last commented by a user?:
      true
    • Sprint:

      Description

      After upgrade Hibernate ORM from 5.0.2 to 5.0.3 I can't make to work JPQL query which uses Enum value with AttributeConverter as part of WHERE clause.

      Given this classes:

      package point.data.jpa.entities;
      
      public class DeskTransaction {
      
        public enum Type {
          TYPE1(1), TYPE2(2);
          private int code;
          private static Map<Integer, Type> typesByCode = new HashMap<>();
          static {
            for (Type type : Type.values()) {
              typesByCode.put(type.code, type);
            }
          }
          public Type(int code) {
            this.code = code;
          }
          public int code getCode() {
            return this.code;
          }
          public static Type fromCode(int code) {
            return typesByCode.get(code);
          }
        }
      
        @Converter(autoApply = true)
        public static class TypeConverter implements AttributeConverter<Type, Integer> {
          @Override
          public Integer convertToDatabaseColumn(Type attribute) {
            return attribute == null ? null : attribute.getCode();
          }
          @Override
          public Type convertToEntityAttribute(Integer dbData) {
            return dbData == null ? null : Type.fromCode(dbData);
          }
        }
      
        @Column(nullable = false)
        private Type type;
      
        @ManyToOne(optional = true)
        @JoinColumn(name = "worker_id")
        private Employee employee;
      
        @Column(name = "money", nullable = false)
        private BigDecimal sum;
      
        // getters and setters
      
      }
      

      Before 5.0.3 (up to 5.0.2 inclusive) this JPQL query works (in 4.x it also worked fine):
      SELECT dt.employee, -SUM(dt.sum) FROM point.data.jpa.entities.DeskTransaction dt WHERE dt.type = 1 GROUP BY dt.employee

      After upgrading to 5.0.3 it don't work anymore and raises exception at application launch:

      Caused by: org.hibernate.QueryException: AttributeConverter domain-model attribute type [point.data.jpa.entities.DeskTransaction$Type] did not match query literal type [java.lang.Integer]

      I think that before 5.0.3 AttributeConverters were not applied for this JPQL WHERE clause so literal "1" worked because in DB this is INTEGER field. So I tried to replace literal "1" to Enum in this query.

      I tried this:
      SELECT dt.employee, -SUM(dt.sum) FROM point.data.jpa.entities.DeskTransaction dt WHERE dt.type = TYPE1 GROUP BY dt.employee
      In this case application starts fine but when this query executes it raises the exception:

      Column "TYPE1" not found; SQL statement:
      select desktransa0_.worker_id as col_0_0_, -sum(desktransa0_.money) as col_1_0_, employee1_.id as id1_30_, employee1_.enable_adminka as enable_a2_30_, employee1_.enable_switch as enable_s3_30_, employee1_.enable_vpn as enable_v4_30_, employee1_.active as active5_30_, employee1_.birthday as birthday6_30_, employee1_.firstname as firstnam7_30_, employee1_.lastname as lastname8_30_, employee1_.login as login9_30_, employee1_.password as passwor10_30_, employee1_.patronymic as patrony11_30_, employee1_.position as positio12_30_, employee1_.com_config_notifications as com_con13_30_, employee1_.ip_address as ip_addr14_30_ from buhuchet desktransa0_ inner join workers employee1_ on desktransa0_.worker_id=employee1_.id where desktransa0_.type=TYPE1 and (desktransa0_.worker_id is not null) group by desktransa0_.worker_id [42122-190]
      

      (take no note of additional fields as my real DeskTransaction and Employee classes are little bigger)

      The real problem here is desktransa0_.type=TYPE1. Of course this is not correct SQL.

      Then I tried to wrote full qualified class name for enum:
      SELECT dt.employee, -SUM(dt.sum) FROM point.data.jpa.entities.DeskTransaction dt WHERE dt.type = point.data.jpa.entities.DeskTransaction.Type.TYPE1 GROUP BY dt.employee

      This causes exception:

      Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'point.data.jpa.entities.DeskTransaction.Type.TYPE1' [SELECT dt.employee, -SUM(dt.sum) FROM point.data.jpa.entities.DeskTransaction dt WHERE dt.type = point.data.jpa.entities.DeskTransaction.Type.TYPE1 AND dt.employee IS NOT NULL GROUP BY dt.employee]

      Then I changed nested class divider from dot to "$" sign:
      SELECT dt.employee, -SUM(dt.sum) FROM point.data.jpa.entities.DeskTransaction dt WHERE dt.type = point.data.jpa.entities.DeskTransaction$Type.TYPE1 GROUP BY dt.employee

      And finally it works fine!

      I find this last solution while wroting this report and now not sure if it is bug at all. Maybe wroting nested classes in class-loader format with "$" as divider is right solution?

      But even if this is true then when this has been changed? I check all changes between 5.0.2 and 5.0.3 and found only HHH-9074 Closed . But it is for boolean and not enums.

      Maybe it should be documented somewhere as many JPQL queries became broken after upgrading to 5.0.3. I think it is bug that type = 1 worked before (skipping AttributeConverters) but it worked quite a while...

      And maybe it is possible to make type = TYPE1 (without FQCN) also works? If class of type is known at runtime then we can deduce enum class for TYPE1.

        Attachments

          Issue links

            Activity

              People

              • Votes:
                1 Vote for this issue
                Watchers:
                7 Start watching this issue

                Dates

                • Created:
                  Updated: