Potential bug in SearchedCaseExpression type handling
Description
Attachments
1
- 25 Jun 2015, 09:59 AM
Activity
Show:
Andrea Boriero September 4, 2015 at 1:38 PM
Andrea Boriero September 2, 2015 at 2:35 PM
Andrea Boriero June 25, 2015 at 9:51 AM
hi @Sven Linstaedt thanks for the test, may be this can help you with eclipse https://developer.jboss.org/wiki/ContributingToHibernateUsingEclipse
Sven Linstaedt June 15, 2015 at 1:28 PM
Sorry for not supplying a pull request, but I was not able to figure out how to get a working hibernate workspace up and running using Eclipse under Windows.
Interestingly the work around with down casting the value type as mentioned in https://hibernate.atlassian.net/browse/HHH-4700#icft=HHH-4700 and https://hibernate.atlassian.net/browse/HHH-9343#icft=HHH-9343 is not working anymore on the current 4.3.x branch. At least on 4.1.4 it was working.
package test;
public class SelectCaseTest {
@javax.persistence.Entity
public static class Entity {
@Id
private Long id;
@Enumerated(EnumType.STRING)
private EnumValue value;
}
public enum EnumValue {
VALUE_1,
VALUE_2;
}
private static EntityManagerFactory factory;
private EntityManager entityManager;
@BeforeClass
public static void beforeClass() {
factory = Persistence.createEntityManagerFactory("test");
}
@AfterClass
public static void afterClass() {
factory.close();
}
@Before
public void before() {
entityManager = factory.createEntityManager();
}
@After
public void after() {
entityManager.close();
}
@Test
public void selectCaseWithValuesShouldWork() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
Case<EnumValue> selectCase = cb.selectCase();
Predicate somePredicate = cb.equal(cb.literal(1), 1);
selectCase.when(somePredicate, EnumValue.VALUE_1);
selectCase.otherwise(EnumValue.VALUE_2);
CriteriaQuery<Entity> query = cb.createQuery(Entity.class);
Root<Entity> from = query.from(Entity.class);
query.select(from).where(cb.equal(from.get("value"), selectCase));
List<?> result = entityManager.createQuery(query).getResultList();
System.out.println(result);
}
@Test
public void selectCaseWithCastedTypeValuesShouldWork() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
Case<String> selectCase = cb.selectCase();
Predicate somePredicate = cb.equal(cb.literal(1), 1);
selectCase.when(somePredicate, EnumValue.VALUE_1.name());
selectCase.otherwise(EnumValue.VALUE_2.name());
CriteriaQuery<Entity> query = cb.createQuery(Entity.class);
Root<Entity> from = query.from(Entity.class);
query.select(from).where(cb.equal(from.get("value"), selectCase.as(String.class)));
List<?> result = entityManager.createQuery(query).getResultList();
System.out.println(result);
}
@Test
public void simpleSelectCaseWithValuesShouldWork() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
SimpleCase<Integer, EnumValue> selectCase = cb.selectCase(cb.literal(1));
selectCase.when(1, EnumValue.VALUE_1);
selectCase.otherwise(EnumValue.VALUE_2);
CriteriaQuery<Entity> query = cb.createQuery(Entity.class);
Root<Entity> from = query.from(Entity.class);
query.select(from).where(cb.equal(from.get("value"), selectCase));
List<?> result = entityManager.createQuery(query).getResultList();
System.out.println(result);
}
@Test
public void simpleSelectCaseWithCastedTypeValuesShouldWork() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
SimpleCase<Integer, String> selectCase = cb.selectCase(cb.literal(1));
selectCase.when(1, EnumValue.VALUE_1.name());
selectCase.otherwise(EnumValue.VALUE_2.name());
CriteriaQuery<Entity> query = cb.createQuery(Entity.class);
Root<Entity> from = query.from(Entity.class);
query.select(from).where(cb.equal(from.get("value"), selectCase.as(String.class)));
List<?> result = entityManager.createQuery(query).getResultList();
System.out.println(result);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="test"
transaction-type="RESOURCE_LOCAL">
<class>test.SelectCaseTest$Entity</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:file:target/testdb;shutdown=true" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.archive.autodetection" value="class" />
<property name="hibernate.flushMode" value="FLUSH_AUTO" />
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="hibernate.show_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
Andrea Boriero June 9, 2015 at 9:21 AM
Hi @Sven Linstaedt can you provide the test case,
thanks
Fixed
Details
Details
Assignee
Andrea Boriero
Andrea BorieroReporter
Sven Linstaedt
Sven LinstaedtComponents
Fix versions
Affects versions
Priority
Created April 17, 2015 at 12:02 PM
Updated September 30, 2015 at 6:35 PM
Resolved September 4, 2015 at 1:38 PM
While debugging some more sophisticated case-when-then expression compilations, I stumpled upon a potential flaw in
org.hibernate.jpa.criteria.expression.SearchedCaseExpression#javaType
, which possible was introduced to lazily assign the expression's type based on either -case-when result's type or a case-otherwise type.Actually
org.hibernate.jpa.criteria.expression.SearchedCaseExpression#javaType
does get written, but never gets read, so it's more or less dead code. If one requestsSearchedCaseExpression
's type, null will be returned, as the method is implemented inorg.hibernate.jpa.criteria.expression.AbstractTupleElement
(which still references javaType asnull
) and not overriden inSearchedCaseExpression
.I am sure, this was not intended and may lead to bugs. A possible fix would look like either
SearchedCaseExpression
needs to overridegetJavaType()
orSearchedCaseExpression#adjustJavaType(Expression)
needs to delegates the expression's type viaAbstractTupleElement#resetJavaType(Class)
to it's orignal field.wdyt?