HHH-10592 - Query with literal parameter and fails with attribute converter
This commit is contained in:
parent
d79305164b
commit
c76577af57
|
@ -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()
|
||||
)
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue