HHH-11409 - Bind registered collection types using their type handler

This commit is contained in:
Yordan Gigov 2017-01-19 10:08:56 +02:00 committed by Vlad Mihalcea
parent e8d7279736
commit f8570017df
2 changed files with 256 additions and 4 deletions

View File

@ -433,7 +433,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
if ( value instanceof TypedParameterValue ) { if ( value instanceof TypedParameterValue ) {
setParameter( parameter, ( (TypedParameterValue) value ).getValue(), ( (TypedParameterValue) value ).getType() ); 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 ); locateListBinding( parameter ).setBindValues( (Collection) value );
} }
else { else {
@ -451,7 +451,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
else if ( value == null ) { else if ( value == null ) {
locateBinding( parameter ).setBindValue( null, type ); locateBinding( parameter ).setBindValue( null, type );
} }
else if ( value instanceof Collection ) { else if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) {
locateListBinding( parameter ).setBindValues( (Collection) value, type ); locateListBinding( parameter ).setBindValues( (Collection) value, type );
} }
else { else {
@ -479,7 +479,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
final TypedParameterValue typedValueWrapper = (TypedParameterValue) value; final TypedParameterValue typedValueWrapper = (TypedParameterValue) value;
setParameter( name, typedValueWrapper.getValue(), typedValueWrapper.getType() ); setParameter( name, typedValueWrapper.getValue(), typedValueWrapper.getType() );
} }
else if ( value instanceof Collection ) { else if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) {
setParameterList( name, (Collection) value ); setParameterList( name, (Collection) value );
} }
else { else {
@ -496,7 +496,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
final TypedParameterValue typedParameterValue = (TypedParameterValue) value; final TypedParameterValue typedParameterValue = (TypedParameterValue) value;
setParameter( position, typedParameterValue.getValue(), typedParameterValue.getType() ); setParameter( position, typedParameterValue.getValue(), typedParameterValue.getType() );
} }
if ( value instanceof Collection ) { else if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) {
setParameterList( Integer.toString( position ), (Collection) value ); setParameterList( Integer.toString( position ), (Collection) value );
} }
else { else {
@ -1577,4 +1577,8 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
protected ExceptionConverter getExceptionConverter(){ protected ExceptionConverter getExceptionConverter(){
return producer.getExceptionConverter(); return producer.getExceptionConverter();
} }
private boolean isRegisteredAsBasicType(Class cl) {
return producer.getFactory().getTypeResolver().basic( cl.getName() ) != null;
}
} }

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<Long> {
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<LongList> {
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<LongList> {
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> X unwrap(LongList value, Class<X> type, WrapperOptions options) {
if ( value == null ) {
return null;
}
if ( String.class.isAssignableFrom( type ) ) {
return (X) this.toString( value );
}
throw unknownUnwrap( type );
}
@Override
public <X> 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 );
}
}
}
}