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:
{code:java} 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
} {code}
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: {noformat} 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]{noformat}
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:
{noformat} Column " EMPLOYEE_RESPONSIBILITY 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= EMPLOYEE_RESPONSIBILITY TYPE1 and (desktransa0_.worker_id is not null) group by desktransa0_.worker_id [42122-190] {noformat} (take no note of additional fields as my real DeskTransaction and Employee classes are little bigger)
The real problem here is *desktransa0_.type= EMPLOYEE_RESPONSIBILITY 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: {noformat}Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'point.data.jpa.entities.DeskTransaction.Type. EMPLOYEE_RESPONSIBILITY TYPE1 ' [SELECT dt.employee, -SUM(dt.sum) FROM point.data.jpa.entities.DeskTransaction dt WHERE dt.type = point.data.jpa.entities.DeskTransaction.Type. EMPLOYEE_RESPONSIBILITY TYPE1 AND dt.employee IS NOT NULL GROUP BY dt.employee]{noformat}
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. 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}}. |
|