diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/simplecase/BasicSimpleCaseTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/simplecase/BasicSimpleCaseTest.java index 0dc395a478..6dc35e392f 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/simplecase/BasicSimpleCaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/simplecase/BasicSimpleCaseTest.java @@ -6,6 +6,14 @@ */ package org.hibernate.jpa.test.criteria.simplecase; +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.List; + +import javax.persistence.AttributeConverter; +import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.GeneratedValue; @@ -13,22 +21,15 @@ import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Tuple; import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaBuilder.SimpleCase; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Path; import javax.persistence.criteria.Root; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; - -import org.junit.Test; - import org.hibernate.testing.TestForIssue; - -import static javax.persistence.criteria.CriteriaBuilder.SimpleCase; -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; -import static org.junit.Assert.assertEquals; - -import java.util.List; +import org.junit.Test; /** * Mote that these are simply performing syntax checking (can the criteria query @@ -40,7 +41,7 @@ public class BasicSimpleCaseTest extends BaseEntityManagerFunctionalTestCase { @Override protected Class[] getAnnotatedClasses() { - return new Class[] {Customer.class}; + return new Class[] {Customer.class, TestEntity.class}; } @Test @@ -209,6 +210,67 @@ public class BasicSimpleCaseTest extends BaseEntityManagerFunctionalTestCase { assertEquals( EmailType.UNKNOWN, results.get( 2 ).get( 1 ) ); } + @Test + @TestForIssue(jiraKey = "HHH-13199") + public void testCaseEnumInSum() throws Exception { + doInJPA( this::entityManagerFactory, em -> { + // create entities + TestEntity e1 = new TestEntity(); + e1.setEnumField( TestEnum.VAL_1 ); + e1.setValue( 20L ); + em.persist( e1 ); + + TestEntity e2 = new TestEntity(); + e2.setEnumField( TestEnum.VAL_2 ); + e2.setValue( 10L ); + em.persist( e2 ); + } ); + + doInJPA( this::entityManagerFactory, em -> { + // Works in previous version (e.g. Hibernate 5.3.7.Final) + // Fails in Hibernate 5.4.0.Final + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery query = cb.createTupleQuery(); + Root r = query.from( TestEntity.class ); + + CriteriaBuilder.Case case1 = cb.selectCase(); + case1.when( cb.equal( r. get( "enumField" ), cb.literal( TestEnum.VAL_1 ) ), + r. get( "value" ) ); + case1.otherwise( cb.nullLiteral( Long.class ) ); + + CriteriaBuilder.Case case2 = cb.selectCase(); + case2.when( cb.equal( r. get( "enumField" ), cb.literal( TestEnum.VAL_2 ) ), + r. get( "value" ) ); + case2.otherwise( cb.nullLiteral( Long.class ) ); + + /* + * Forces enums to be bound as parameters, so SQL is something like + * "SELECT enumfield AS enumField, SUM(CASE WHEN enumfield = ? THEN value + * ELSE NULL END) AS VAL_1, SUM(CASE WHEN enumfield =? THEN value ELSE NULL END) AS VAL_1 FROM TestEntity + * GROUP BY enumfield" + */ + query + .select( cb.tuple( r. get( "enumField" ).alias( "enumField" ), + cb.sum( case1 ).alias( "VAL_1" ), + cb.sum( case2 ).alias( "VAL_2" ) ) ) + .groupBy( r. get( "enumField" ) ); + + List list = em.createQuery( query ).getResultList(); + assertEquals( 2, list.size() ); + for ( Tuple tuple : list ) { + TestEnum enumVal = tuple.get( "enumField", TestEnum.class ); + if ( enumVal == TestEnum.VAL_1 ) { + assertEquals( 20L, tuple.get( "VAL_1", Long.class ).longValue() ); + assertNull( tuple.get( "VAL_2", Long.class ) ); + } + else if ( enumVal == TestEnum.VAL_2 ) { + assertNull( tuple.get( "VAL_1", Long.class ) ); + assertEquals( 10L, tuple.get( "VAL_2", Long.class ).longValue() ); + } + } + } ); + } + @Entity(name = "Customer") @Table(name = "customer") public static class Customer { @@ -237,4 +299,72 @@ public class BasicSimpleCaseTest extends BaseEntityManagerFunctionalTestCase { public enum EmailType { LONG, NORMAL, UNKNOWN } + + @Entity(name = "TestEntity") + public static class TestEntity { + @Id + @GeneratedValue + private long id; + + @Convert(converter = TestEnumConverter.class) + private TestEnum enumField; + + private Long value; + + public long getId() { + return id; + } + + public TestEnum getEnumField() { + return enumField; + } + + public void setEnumField(TestEnum enumField) { + this.enumField = enumField; + } + + public Long getValue() { + return value; + } + + public void setValue(Long value) { + this.value = value; + } + } + + public static enum TestEnum { + VAL_1("1"), + VAL_2("2"); + + private final String value; + + private TestEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static TestEnum fromValue(String value) { + if (value.equals(VAL_1.value)) { + return VAL_1; + } else if (value.equals(VAL_2.value)) { + return VAL_2; + } + return null; + } + } + + public static class TestEnumConverter implements AttributeConverter { + @Override + public String convertToDatabaseColumn(TestEnum attribute) { + return attribute == null ? null : attribute.getValue(); + } + + @Override + public TestEnum convertToEntityAttribute(String dbData) { + return dbData == null ? null : TestEnum.fromValue(dbData); + } + } }