Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
HHH-9074 - HQL Query with boolean and @convert
(cherry picked from commit ac2f068)
  • Loading branch information
sebersole committed Oct 8, 2015
1 parent 4ee6b88 commit d8ab9c0
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 30 deletions.
Expand Up @@ -11,6 +11,7 @@
import org.hibernate.type.LiteralType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter;

/**
* Represents a boolean literal within a query.
Expand All @@ -21,13 +22,18 @@ public class BooleanLiteralNode extends LiteralNode implements ExpectedTypeAware
private Type expectedType;

public Type getDataType() {
return expectedType == null ? StandardBasicTypes.BOOLEAN : expectedType;
return getExpectedType() == null ? StandardBasicTypes.BOOLEAN : getExpectedType();
}

public Boolean getValue() {
return getType() == TRUE ;
}

@Override
public void setText(String s) {
super.setText( s );
}

@Override
public void setExpectedType(Type expectedType) {
this.expectedType = expectedType;
Expand All @@ -41,16 +47,20 @@ public Type getExpectedType() {
@Override
@SuppressWarnings( {"unchecked"})
public String getRenderText(SessionFactoryImplementor sessionFactory) {
try {
return typeAsLiteralType().objectToSQLString( getValue(), sessionFactory.getDialect() );
final boolean literalValue = getValue();

if ( expectedType instanceof AttributeConverterTypeAdapter ) {
return determineConvertedValue( (AttributeConverterTypeAdapter) expectedType, literalValue );
}
catch( Exception t ) {
throw new QueryException( "Unable to render boolean literal value", t );
else if ( expectedType instanceof LiteralType ) {
try {
return ( (LiteralType) expectedType ).objectToSQLString( getValue(), sessionFactory.getDialect() );
}
catch( Exception t ) {
throw new QueryException( "Unable to render boolean literal value using expected LiteralType", t );
}
}
}

private LiteralType typeAsLiteralType() {
return (LiteralType) getDataType();

return sessionFactory.getDialect().toBooleanValueString( literalValue );
}
}
Expand Up @@ -7,10 +7,13 @@
package org.hibernate.hql.internal.ast.tree;

import java.sql.Types;
import java.util.Locale;
import javax.persistence.AttributeConverter;

import org.hibernate.QueryException;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.ast.util.ColumnHelper;
import org.hibernate.type.LiteralType;
import org.hibernate.type.SingleColumnType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
Expand All @@ -32,8 +35,8 @@ public void setScalarColumnText(int i) throws SemanticException {
}

public Type getDataType() {
if ( expectedType != null ) {
return expectedType;
if ( getExpectedType() != null ) {
return getExpectedType();
}

switch ( getType() ) {
Expand Down Expand Up @@ -81,21 +84,36 @@ public void setExpectedType(Type expectedType) {

if ( AttributeConverterTypeAdapter.class.isInstance( expectedType ) ) {
final AttributeConverterTypeAdapter adapterType = (AttributeConverterTypeAdapter) expectedType;
if ( getDataType().getReturnedClass().equals( adapterType.getModelType() ) ) {
// apply the converter
final AttributeConverter converter = ( (AttributeConverterTypeAdapter) expectedType ).getAttributeConverter();
final Object converted = converter.convertToDatabaseColumn( getLiteralValue() );
if ( isCharacterData( adapterType.sqlType() ) ) {
setText( "'" + converted.toString() + "'" );
}
else {
setText( converted.toString() );
}
}
setText( determineConvertedValue( adapterType, getLiteralValue() ) );
this.expectedType = expectedType;
}
}

@SuppressWarnings("unchecked")
protected String determineConvertedValue(AttributeConverterTypeAdapter converterTypeAdapter, Object literalValue) {
if ( getDataType().getReturnedClass().equals( converterTypeAdapter.getModelType() ) ) {
// apply the converter
final AttributeConverter converter = converterTypeAdapter.getAttributeConverter();
final Object converted = converter.convertToDatabaseColumn( getLiteralValue() );
if ( isCharacterData( converterTypeAdapter.sqlType() ) ) {
return "'" + converted.toString() + "'";
}
else {
return converted.toString();
}
}
else {
throw new QueryException(
String.format(
Locale.ROOT,
"AttributeConverter domain-model attribute type [%s] did not match query literal type [%s]",
converterTypeAdapter.getModelType().getName(),
getDataType().getReturnedClass().getName()
)
);
}
}

private boolean isCharacterData(int typeCode) {
return Types.VARCHAR == typeCode
|| Types.CHAR == typeCode
Expand Down
Expand Up @@ -19,6 +19,7 @@
import org.hibernate.hql.internal.antlr.SqlTokenTypes;
import org.hibernate.hql.internal.ast.HqlSqlWalker;
import org.hibernate.hql.internal.ast.InvalidPathException;
import org.hibernate.hql.internal.ast.tree.BooleanLiteralNode;
import org.hibernate.hql.internal.ast.tree.DotNode;
import org.hibernate.hql.internal.ast.tree.FromClause;
import org.hibernate.hql.internal.ast.tree.IdentNode;
Expand Down Expand Up @@ -184,17 +185,10 @@ else if ( value instanceof Float ) {
}

public void processBoolean(AST constant) {
// TODO: something much better - look at the type of the other expression!
// TODO: Have comparisonExpression and/or arithmeticExpression rules complete the resolution of boolean nodes.
String replacement = (String) walker.getTokenReplacements().get( constant.getText() );
if ( replacement != null ) {
constant.setText( replacement );
}
else {
boolean bool = "true".equals( constant.getText().toLowerCase(Locale.ROOT) );
Dialect dialect = walker.getSessionFactoryHelper().getFactory().getDialect();
constant.setText( dialect.toBooleanValueString( bool ) );
}
}

private void processLiteral(AST constant) {
Expand Down
Expand Up @@ -8,13 +8,15 @@

import javax.persistence.AttributeConverter;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Converter;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.HibernateException;
import org.hibernate.Session;

import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
Expand All @@ -23,6 +25,7 @@
import org.junit.Test;

import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

/**
* Test AttributeConverter functioning in various Query scenarios.
Expand All @@ -34,7 +37,7 @@ public class QueryTest extends BaseNonConfigCoreFunctionalTestCase {
public static final float SALARY = 267.89f;

@Test
public void testJpqlLiteral() {
public void testJpqlFloatLiteral() {
Session session = openSession();
session.getTransaction().begin();
Employee jDoe = (Employee) session.createQuery( "from Employee e where e.salary = " + SALARY + "f" ).uniqueResult();
Expand All @@ -43,6 +46,16 @@ public void testJpqlLiteral() {
session.close();
}

@Test
public void testJpqlBooleanLiteral() {
Session session = openSession();
session.getTransaction().begin();
assertNotNull( session.createQuery( "from Employee e where e.active = true" ).uniqueResult() );
assertNull( session.createQuery( "from Employee e where e.active = false" ).uniqueResult() );
session.getTransaction().commit();
session.close();
}

@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Employee.class, SalaryConverter.class };
Expand Down Expand Up @@ -74,6 +87,8 @@ public static class Employee {
@Embedded
public Name name;
public Float salary;
@Convert( converter = BooleanConverter.class )
public boolean active = true;

public Employee() {
}
Expand Down Expand Up @@ -125,4 +140,29 @@ public Float convertToEntityAttribute(Long dbData) {
return new Float( ( dbData.floatValue() ) / 100 );
}
}

public static class BooleanConverter implements AttributeConverter<Boolean,Integer> {

@Override
public Integer convertToDatabaseColumn(Boolean attribute) {
if ( attribute == null ) {
return null;
}
return attribute ? 1 : 0;
}

@Override
public Boolean convertToEntityAttribute(Integer dbData) {
if ( dbData == null ) {
return null;
}
else if ( dbData == 0 ) {
return false;
}
else if ( dbData == 1 ) {
return true;
}
throw new HibernateException( "Unexpected boolean numeric; expecting null, 0 or 1, but found " + dbData );
}
}
}

0 comments on commit d8ab9c0

Please sign in to comment.