HHH-10592 - Query with literal parameter and fails with attribute converter

This commit is contained in:
Janario Oliveira 2016-03-05 18:02:35 -03:00 committed by Vlad Mihalcea
parent d79305164b
commit c76577af57
2 changed files with 366 additions and 2 deletions

View File

@ -13,7 +13,6 @@ 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;
@ -102,12 +101,21 @@ public class LiteralNode extends AbstractSelectExpression implements HqlSqlToken
return converted.toString();
}
}
else if ( getDataType().getReturnedClass().equals( converterTypeAdapter.getJdbcType() ) ) {
if ( isCharacterData( converterTypeAdapter.sqlType() ) ) {
return "'" + literalValue.toString() + "'";
}
else {
return literalValue.toString();
}
}
else {
throw new QueryException(
String.format(
Locale.ROOT,
"AttributeConverter domain-model attribute type [%s] did not match query literal type [%s]",
"AttributeConverter domain-model attribute type [%s] and JDBC type [%s] did not match query literal type [%s]",
converterTypeAdapter.getModelType().getName(),
converterTypeAdapter.getJdbcType().getName(),
getDataType().getReturnedClass().getName()
)
);

View File

@ -0,0 +1,356 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.converter.literal;
import javax.persistence.AttributeConverter;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Converter;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.Query;
import org.hibernate.QueryException;
import org.hibernate.Session;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Janario Oliveira
*/
public class QueryLiteralTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {
EntityConverter.class, NumberIntegerConverter.class, NumberStringConverter.class,
StringWrapperConverter.class, IntegerWrapperConverter.class
};
}
@Test
public void testIntegerWrapper() {
EntityConverter entity = new EntityConverter();
entity.setIntegerWrapper( new IntegerWrapper( 10 ) );
save( entity );
entity = find( entity.getId(), "e.integerWrapper=10" );
assertNotNull( entity );
assertEquals( 10, entity.getIntegerWrapper().getValue() );
}
@Test
public void testIntegerWrapperThrowsException() {
EntityConverter entity = new EntityConverter();
entity.setIntegerWrapper( new IntegerWrapper( 10 ) );
save( entity );
try {
find( entity.getId(), "e.integerWrapper='10'" );
fail("Should throw QueryException!");
}
catch (QueryException e) {
assertTrue( e.getMessage().contains( "AttributeConverter domain-model attribute type [org.hibernate.test.converter.literal.QueryLiteralTest$IntegerWrapper] and JDBC type [java.lang.Integer] did not match query literal type [java.lang.String]" ) );
}
}
@Test
public void testStringWrapper() {
EntityConverter entity = new EntityConverter();
entity.setStringWrapper( new StringWrapper( "TEN" ) );
save( entity );
entity = find( entity.getId(), "e.stringWrapper='TEN'" );
assertNotNull( entity );
assertEquals( "TEN", entity.getStringWrapper().getValue() );
}
@Test
public void testSameTypeConverter() {
EntityConverter entity = new EntityConverter();
entity.setSameTypeConverter( "HUNDRED" );
save( entity );
entity = find( entity.getId(), "e.sameTypeConverter='HUNDRED'" );
assertNotNull( entity );
assertEquals( "HUNDRED", entity.getSameTypeConverter() );
Session session = openSession();
String value = (String) session.createSQLQuery(
"select e.same_type_converter from entity_converter e where e.id=:id" )
.setParameter( "id", entity.getId() )
.uniqueResult();
assertEquals( "VALUE_HUNDRED", value );
session.close();
}
@Test
public void testEnumOrdinal() {
EntityConverter entity = new EntityConverter();
entity.setLetterOrdinal( Letter.B );
save( entity );
entity = find( entity.getId(), "e.letterOrdinal=" + Letter.B.ordinal() );
assertNotNull( entity );
assertEquals( Letter.B, entity.getLetterOrdinal() );
}
@Test
public void testEnumString() {
EntityConverter entity = new EntityConverter();
entity.setLetterString( Letter.C );
save( entity );
entity = find( entity.getId(), "e.letterString='" + Letter.C.name() + "'" );
assertNotNull( entity );
assertEquals( Letter.C, entity.getLetterString() );
}
@Test
public void testNumberImplicit() {
EntityConverter entity = new EntityConverter();
entity.setNumbersImplicit( Numbers.THREE );
save( entity );
entity = find( entity.getId(), "e.numbersImplicit=" + ( Numbers.THREE.ordinal() + 1 ) );
assertNotNull( entity );
assertEquals( Numbers.THREE, entity.getNumbersImplicit() );
}
@Test
public void testNumberImplicitOverrided() {
EntityConverter entity = new EntityConverter();
entity.setNumbersImplicitOverrided( Numbers.TWO );
save( entity );
entity = find( entity.getId(), "e.numbersImplicitOverrided='" + ( Numbers.TWO.ordinal() + 1 ) + "'" );
assertNotNull( entity );
assertEquals( Numbers.TWO, entity.getNumbersImplicitOverrided() );
}
private void save(EntityConverter entity) {
Session session = openSession();
session.beginTransaction();
session.persist( entity );
session.getTransaction().commit();
session.close();
}
private EntityConverter find(int id, String queryLiteral) {
Session session = openSession();
Query query = session.createQuery(
"select e from EntityConverter e where e.id=:id and " + queryLiteral );
query.setParameter( "id", id );
EntityConverter entity = (EntityConverter) query.uniqueResult();
session.close();
return entity;
}
public enum Letter {
A, B, C
}
public enum Numbers {
ONE, TWO, THREE
}
@Converter(autoApply = true)
public static class NumberIntegerConverter implements AttributeConverter<Numbers, Integer> {
@Override
public Integer convertToDatabaseColumn(Numbers attribute) {
return attribute == null ? null : attribute.ordinal() + 1;
}
@Override
public Numbers convertToEntityAttribute(Integer dbData) {
return dbData == null ? null : Numbers.values()[dbData - 1];
}
}
@Converter
public static class NumberStringConverter implements AttributeConverter<Numbers, String> {
@Override
public String convertToDatabaseColumn(Numbers attribute) {
return attribute == null ? null : Integer.toString( attribute.ordinal() + 1 );
}
@Override
public Numbers convertToEntityAttribute(String dbData) {
return dbData == null ? null : Numbers.values()[Integer.parseInt( dbData ) - 1];
}
}
@Converter(autoApply = true)
public static class IntegerWrapperConverter implements AttributeConverter<IntegerWrapper, Integer> {
@Override
public Integer convertToDatabaseColumn(IntegerWrapper attribute) {
return attribute == null ? null : attribute.getValue();
}
@Override
public IntegerWrapper convertToEntityAttribute(Integer dbData) {
return dbData == null ? null : new IntegerWrapper( dbData );
}
}
@Converter(autoApply = true)
public static class StringWrapperConverter implements AttributeConverter<StringWrapper, String> {
@Override
public String convertToDatabaseColumn(StringWrapper attribute) {
return attribute == null ? null : attribute.getValue();
}
@Override
public StringWrapper convertToEntityAttribute(String dbData) {
return dbData == null ? null : new StringWrapper( dbData );
}
}
@Converter
public static class PreFixedStringConverter implements AttributeConverter<String, String> {
@Override
public String convertToDatabaseColumn(String attribute) {
return attribute == null ? null : "VALUE_" + attribute;
}
@Override
public String convertToEntityAttribute(String dbData) {
return dbData == null ? null : dbData.substring( 6 );
}
}
@Entity(name = "EntityConverter")
@Table(name = "entity_converter")
public static class EntityConverter {
@Id
@GeneratedValue
private Integer id;
private Letter letterOrdinal;
@Enumerated(EnumType.STRING)
private Letter letterString;
private Numbers numbersImplicit;
@Convert(converter = NumberStringConverter.class)
private Numbers numbersImplicitOverrided;
private IntegerWrapper integerWrapper;
private StringWrapper stringWrapper;
@Convert(converter = PreFixedStringConverter.class)
@Column(name = "same_type_converter")
private String sameTypeConverter;
public Integer getId() {
return id;
}
public Letter getLetterOrdinal() {
return letterOrdinal;
}
public void setLetterOrdinal(Letter letterOrdinal) {
this.letterOrdinal = letterOrdinal;
}
public Letter getLetterString() {
return letterString;
}
public void setLetterString(Letter letterString) {
this.letterString = letterString;
}
public Numbers getNumbersImplicit() {
return numbersImplicit;
}
public void setNumbersImplicit(Numbers numbersImplicit) {
this.numbersImplicit = numbersImplicit;
}
public Numbers getNumbersImplicitOverrided() {
return numbersImplicitOverrided;
}
public void setNumbersImplicitOverrided(Numbers numbersImplicitOverrided) {
this.numbersImplicitOverrided = numbersImplicitOverrided;
}
public IntegerWrapper getIntegerWrapper() {
return integerWrapper;
}
public void setIntegerWrapper(IntegerWrapper integerWrapper) {
this.integerWrapper = integerWrapper;
}
public StringWrapper getStringWrapper() {
return stringWrapper;
}
public void setStringWrapper(StringWrapper stringWrapper) {
this.stringWrapper = stringWrapper;
}
public String getSameTypeConverter() {
return sameTypeConverter;
}
public void setSameTypeConverter(String sameTypeConverter) {
this.sameTypeConverter = sameTypeConverter;
}
}
public static class IntegerWrapper {
private final int value;
public IntegerWrapper(int value) {
this.value = value;
}
public int getValue() {
return value;
}
@Override
public String toString() {
return String.format( "IntegerWrapper{value=%d}", value);
}
}
public static class StringWrapper {
private final String value;
public StringWrapper(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
}