From f8570017dfc22b33b494d885e1896a8c73d3489c Mon Sep 17 00:00:00 2001 From: Yordan Gigov Date: Thu, 19 Jan 2017 10:08:56 +0200 Subject: [PATCH] HHH-11409 - Bind registered collection types using their type handler --- .../query/internal/AbstractProducedQuery.java | 12 +- .../type/LongListTypeContributorTest.java | 248 ++++++++++++++++++ 2 files changed, 256 insertions(+), 4 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/type/LongListTypeContributorTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java index 8ba2b9ed62..66c1a8b91e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java @@ -433,7 +433,7 @@ public abstract class AbstractProducedQuery implements QueryImplementor { if ( value instanceof TypedParameterValue ) { setParameter( parameter, ( (TypedParameterValue) value ).getValue(), ( (TypedParameterValue) value ).getType() ); } - else if ( value instanceof Collection ) { + else if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) { locateListBinding( parameter ).setBindValues( (Collection) value ); } else { @@ -451,7 +451,7 @@ public abstract class AbstractProducedQuery implements QueryImplementor { else if ( value == null ) { locateBinding( parameter ).setBindValue( null, type ); } - else if ( value instanceof Collection ) { + else if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) { locateListBinding( parameter ).setBindValues( (Collection) value, type ); } else { @@ -479,7 +479,7 @@ public abstract class AbstractProducedQuery implements QueryImplementor { final TypedParameterValue typedValueWrapper = (TypedParameterValue) value; setParameter( name, typedValueWrapper.getValue(), typedValueWrapper.getType() ); } - else if ( value instanceof Collection ) { + else if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) { setParameterList( name, (Collection) value ); } else { @@ -496,7 +496,7 @@ public abstract class AbstractProducedQuery implements QueryImplementor { final TypedParameterValue typedParameterValue = (TypedParameterValue) value; setParameter( position, typedParameterValue.getValue(), typedParameterValue.getType() ); } - if ( value instanceof Collection ) { + else if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) { setParameterList( Integer.toString( position ), (Collection) value ); } else { @@ -1577,4 +1577,8 @@ public abstract class AbstractProducedQuery implements QueryImplementor { protected ExceptionConverter getExceptionConverter(){ return producer.getExceptionConverter(); } + + private boolean isRegisteredAsBasicType(Class cl) { + return producer.getFactory().getTypeResolver().basic( cl.getName() ) != null; + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/type/LongListTypeContributorTest.java b/hibernate-core/src/test/java/org/hibernate/test/type/LongListTypeContributorTest.java new file mode 100644 index 0000000000..e102d6c149 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/type/LongListTypeContributorTest.java @@ -0,0 +1,248 @@ +/* + * 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 . + */ +package org.hibernate.test.type; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Map; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.boot.model.TypeContributor; +import org.hibernate.jpa.boot.spi.TypeContributorList; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.AbstractSingleColumnStandardBasicType; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; +import org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry; + +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; + +public class LongListTypeContributorTest extends BaseEntityManagerFunctionalTestCase { + + @Override + public Class[] getAnnotatedClasses() { + return new Class[] { + SpecialItem.class, + }; + } + + @Override + protected void addConfigOptions(Map options) { + super.addConfigOptions( options ); + options.put( "hibernate.type_contributors", (TypeContributorList) () -> Arrays.asList( + new StringifiedCollectionTypeContributor() + ) ); + } + + @Test + @TestForIssue(jiraKey = "HHH-11409") + public void testParameterRegisterredCollection() { + + LongList longList = new LongList(5L, 11L, 6123L, -61235L, 24L); + + doInJPA( this::entityManagerFactory, em -> { + SpecialItem item = new SpecialItem( "LongList", longList ); + em.persist( item ); + } ); + + doInJPA( this::entityManagerFactory, em -> { + + SpecialItem item = (SpecialItem) em.createNativeQuery( + "SELECT * FROM special_table WHERE longList = ?", SpecialItem.class ) + .setParameter(1, longList) + .getSingleResult(); + + assertEquals( "LongList", item.getName() ); + } ); + + doInJPA( this::entityManagerFactory, em -> { + SpecialItem item = (SpecialItem) em.createNativeQuery( + "SELECT * FROM special_table WHERE longList = :longList", SpecialItem.class ) + .setParameter("longList", longList) + .getSingleResult(); + + assertEquals( "LongList", item.getName() ); + } ); + } + + @Entity(name = "SpecialItem") + @Table(name = "special_table") + public static class SpecialItem implements Serializable { + + @Id + @Column(length = 30) + private String name; + + @Column(columnDefinition = "text") + private LongList longList; + + public SpecialItem() { + } + + public SpecialItem(String name, LongList longList) { + this.name = name; + this.longList = longList; + } + + public LongList getLongList() { + return longList; + } + + public void setLongList(LongList longList) { + this.longList = longList; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + public static class LongList extends java.util.ArrayList { + + public LongList() { + super(); + } + + public LongList(int initialCapacity) { + super( initialCapacity ); + } + + public LongList(Long... longs) { + super( longs.length ); + for ( Long l : longs ) { + this.add( l ); + } + } + } + + public static class StringifiedCollectionTypeContributor implements TypeContributor { + + @Override + public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + JavaTypeDescriptorRegistry.INSTANCE.addDescriptor( StringifiedCollectionJavaTypeDescriptor.INSTANCE ); + typeContributions.contributeType( StringifiedCollectionType.INSTANCE ); + } + + private static class StringifiedCollectionType + extends AbstractSingleColumnStandardBasicType { + + private final String[] regKeys; + private final String name; + + public static final StringifiedCollectionType INSTANCE = new StringifiedCollectionType(); + + public StringifiedCollectionType() { + super( org.hibernate.type.descriptor.sql.LongVarcharTypeDescriptor.INSTANCE, + StringifiedCollectionJavaTypeDescriptor.INSTANCE ); + regKeys = new String[]{ LongList.class.getName() }; + name = "StringifiedCollection"; + } + + @Override + public String getName() { + return name; + } + + @Override + public String[] getRegistrationKeys() { + return regKeys.clone(); + } + + @Override + protected boolean registerUnderJavaType() { + return true; + } + } + + private static class StringifiedCollectionJavaTypeDescriptor extends AbstractTypeDescriptor { + + public static StringifiedCollectionJavaTypeDescriptor INSTANCE = new StringifiedCollectionJavaTypeDescriptor(); + + public StringifiedCollectionJavaTypeDescriptor() { + super( LongList.class ); + } + + @Override + public String toString(LongList value) { + if ( value == null ) { + return "null"; + } + StringBuilder sb = new StringBuilder(); + sb.append( '[' ); + String glue = ""; + for ( Long v : value ) { + sb.append( glue ).append( v ); + glue = ","; + } + sb.append( ']' ); + return sb.toString(); + } + + @Override + public LongList fromString(String string) { + if ( string == null || "null".equals( string ) ) { + return null; + } + + if ( string.length() <= 2 ) { + return new LongList(); + } + + String[] parts = string.substring( 1, string.length() - 1 ).split( "," ); + LongList results = new LongList( parts.length ); + + for ( String part : parts ) { + results.add( Long.valueOf( part ) ); + } + + return results; + } + + @Override + public X unwrap(LongList value, Class type, WrapperOptions options) { + if ( value == null ) { + return null; + } + + if ( String.class.isAssignableFrom( type ) ) { + return (X) this.toString( value ); + } + + throw unknownUnwrap( type ); + } + + @Override + public LongList wrap(X value, WrapperOptions options) { + if ( value == null ) { + return null; + } + + Class type = value.getClass(); + + if ( String.class.isAssignableFrom( type ) ) { + String s = (String) value; + return this.fromString( s ); + } + + throw unknownWrap( type ); + } + } + } +}