Serialize constants in case constructs as literals for Hibernate

This commit is contained in:
Timo Westkämper 2014-11-18 23:28:06 +02:00
parent 9a8500ce42
commit 41b73ea816
5 changed files with 98 additions and 22 deletions

View File

@ -141,4 +141,9 @@ public class HQLTemplates extends JPQLTemplates {
return true;
}
@Override
public boolean isCaseWithLiterals() {
return true;
}
}

View File

@ -79,6 +79,8 @@ public class JPQLSerializer extends SerializerBase<JPQLSerializer> {
private boolean inProjection = false;
private boolean inCaseOperation = false;
static{
joinTypes.put(JoinType.DEFAULT, COMMA);
joinTypes.put(JoinType.FULLJOIN, "\n full join ");
@ -279,23 +281,64 @@ public class JPQLSerializer extends SerializerBase<JPQLSerializer> {
@Override
public void visitConstant(Object constant) {
boolean wrap = templates.wrapConstant(constant);
if (wrap) {
append("(");
}
append("?");
if (!getConstantToLabel().containsKey(constant)) {
final String constLabel = String.valueOf(getConstantToLabel().size()+1);
getConstantToLabel().put(constant, constLabel);
append(constLabel);
if (inCaseOperation && templates.isCaseWithLiterals()) {
visitLiteral(constant);
} else {
append(getConstantToLabel().get(constant));
boolean wrap = templates.wrapConstant(constant);
if (wrap) {
append("(");
}
append("?");
if (!getConstantToLabel().containsKey(constant)) {
final String constLabel = String.valueOf(getConstantToLabel().size()+1);
getConstantToLabel().put(constant, constLabel);
append(constLabel);
} else {
append(getConstantToLabel().get(constant));
}
if (wrap) {
append(")");
}
}
if (wrap) {
append(")");
}
public void visitLiteral(Object constant) {
if (constant instanceof Boolean) {
append(constant.toString());
} else if (constant instanceof Number) {
append(constant.toString());
} else if (constant instanceof String) {
append("'");
append(escapeLiteral(constant.toString()));
append("'");
} else if (constant instanceof Enum) {
append(constant.getClass().getName());
append(".");
append(((Enum) constant).name());
} else {
// TODO date time literals
throw new IllegalArgumentException("Unsupported constant " + constant);
}
}
private String escapeLiteral(String str) {
StringBuilder builder = new StringBuilder();
for (char ch : str.toCharArray()) {
if (ch == '\n') {
builder.append("\\n");
continue;
} else if (ch == '\r') {
builder.append("\\r");
continue;
} else if (ch == '\'') {
builder.append("''");
continue;
}
builder.append(ch);
}
return builder.toString();
}
@Override
public Void visit(ParamExpression<?> param, Void context) {
append("?");
@ -336,7 +379,9 @@ public class JPQLSerializer extends SerializerBase<JPQLSerializer> {
@Override
@SuppressWarnings("unchecked")
protected void visitOperation(Class<?> type, Operator<?> operator, List<? extends Expression<?>> args) {
boolean old = wrapElements;
boolean oldInCaseOperation = inCaseOperation;
inCaseOperation = inCaseOperation || operator.equals(Ops.CASE) || operator.equals(Ops.CASE_EQ);
boolean oldWrapElements = wrapElements;
wrapElements = templates.wrapElements(operator);
if (operator == Ops.EQ && args.get(1) instanceof Operation &&
@ -387,7 +432,8 @@ public class JPQLSerializer extends SerializerBase<JPQLSerializer> {
super.visitOperation(type, operator, args);
}
wrapElements = old;
inCaseOperation = oldInCaseOperation;
wrapElements = oldWrapElements;
}
private void visitNumCast(List<? extends Expression<?>> args) {

View File

@ -183,4 +183,8 @@ public class JPQLTemplates extends Templates {
return queryHandler;
}
public boolean isCaseWithLiterals() {
return false;
}
}

View File

@ -303,19 +303,11 @@ public abstract class AbstractJPATest {
}
@Test
@NoHibernate // https://hibernate.atlassian.net/browse/HHH-4700
@NoBatooJPA
public void Case() {
query().from(cat).list(cat.name.when("Bob").then(1).otherwise(2));
}
@Test(expected=ClassCastException.class)
@NoEclipseLink
@NoBatooJPA
public void Case_Hibernate() {
query().from(cat).list(cat.name.when("Bob").then(1).otherwise(2));
}
@Test
public void Case2() {
query().from(cat)

View File

@ -19,6 +19,7 @@ import com.mysema.query.DefaultQueryMetadata;
import com.mysema.query.JoinType;
import com.mysema.query.QueryMetadata;
import com.mysema.query.domain.QCat;
import com.mysema.query.jpa.domain.JobFunction;
import com.mysema.query.jpa.domain.Location;
import com.mysema.query.jpa.domain.QDomesticCat;
import com.mysema.query.jpa.domain.QEmployee;
@ -223,4 +224,32 @@ public class JPQLSerializerTest {
assertEquals("select cat_\nfrom Cat cat_\n inner join cat_.mate on cat_.mate.alive",
serializer.toString());
}
@Test
public void visitLiteral_boolean() {
JPQLSerializer serializer = new JPQLSerializer(HQLTemplates.DEFAULT);
serializer.visitLiteral(Boolean.TRUE);
assertEquals("true", serializer.toString());
}
@Test
public void visitLiteral_number() {
JPQLSerializer serializer = new JPQLSerializer(HQLTemplates.DEFAULT);
serializer.visitLiteral(1.543);
assertEquals("1.543", serializer.toString());
}
@Test
public void visitLiteral_string() {
JPQLSerializer serializer = new JPQLSerializer(HQLTemplates.DEFAULT);
serializer.visitLiteral("abc''def");
assertEquals("'abc''''def'", serializer.toString());
}
@Test
public void visitLiteral_enum() {
JPQLSerializer serializer = new JPQLSerializer(HQLTemplates.DEFAULT);
serializer.visitLiteral(JobFunction.MANAGER);
assertEquals("com.mysema.query.jpa.domain.JobFunction.MANAGER", serializer.toString());
}
}