Skip to content

Commit 9ec8ab5

Browse files
committed
HHH-17355 Support binding single element value for basic plural parameter types
1 parent 3c4fa61 commit 9ec8ab5

17 files changed

+88
-58
lines changed

hibernate-core/src/main/java/org/hibernate/query/spi/QueryParameterBindingValidator.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import org.hibernate.query.BindableType;
1515
import org.hibernate.query.QueryArgumentException;
1616
import org.hibernate.query.sqm.SqmExpressible;
17-
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
1817
import org.hibernate.type.descriptor.java.JavaType;
1918

2019
import jakarta.persistence.TemporalType;
@@ -142,13 +141,6 @@ else if ( temporalType != null ) {
142141

143142
return parameterDeclarationIsTemporal && bindIsTemporal;
144143
}
145-
// Allow binding a single element for a basic plural parameter type
146-
else if ( expectedJavaType instanceof BasicPluralJavaType<?> ) {
147-
final JavaType<?> elementJavaType = ( (BasicPluralJavaType<?>) expectedJavaType ).getElementJavaType();
148-
if ( elementJavaType.isInstance( value ) ) {
149-
return true;
150-
}
151-
}
152144

153145
return false;
154146
}

hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcParameterBindings.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,15 @@ default int registerParametersForEachJdbcValue(
7474
Bindable bindable,
7575
JdbcParametersList jdbcParameters,
7676
SharedSessionContractImplementor session) {
77+
final Object valueToBind;
78+
if ( bindable.getJdbcTypeCount() == 1 ) {
79+
valueToBind = bindable.getSingleJdbcMapping().getMappedJavaType().wrap( value, session );
80+
}
81+
else {
82+
valueToBind = value;
83+
}
7784
return bindable.forEachJdbcValue(
78-
value,
85+
valueToBind,
7986
offset,
8087
jdbcParameters,
8188
session.getFactory().getTypeConfiguration(),

hibernate-core/src/main/java/org/hibernate/type/BasicArrayType.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@
66
*/
77
package org.hibernate.type;
88

9-
import java.lang.reflect.Array;
109
import java.util.Objects;
1110

12-
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1311
import org.hibernate.type.descriptor.java.JavaType;
1412
import org.hibernate.type.descriptor.jdbc.JdbcType;
1513
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
@@ -56,20 +54,6 @@ public <X> BasicType<X> resolveIndicatedType(JdbcTypeIndicators indicators, Java
5654
return (BasicType<X>) this;
5755
}
5856

59-
@Override
60-
public Object disassemble(Object value, SharedSessionContractImplementor session) {
61-
if ( value == null ) {
62-
return null;
63-
}
64-
if ( baseDescriptor.isInstance( (E) value ) ) {
65-
// Support binding a single element as parameter value
66-
final Object array = Array.newInstance( baseDescriptor.getJavaType(), 1 );
67-
Array.set( array, 0, value );
68-
return array;
69-
}
70-
return value;
71-
}
72-
7357
@Override
7458
public boolean equals(Object o) {
7559
return o == this || o.getClass() == BasicArrayType.class

hibernate-core/src/main/java/org/hibernate/type/BasicCollectionType.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@
66
*/
77
package org.hibernate.type;
88

9-
import java.lang.reflect.Array;
109
import java.util.Collection;
1110
import java.util.Objects;
1211

13-
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1412
import org.hibernate.type.descriptor.java.JavaType;
1513
import org.hibernate.type.descriptor.java.spi.BasicCollectionJavaType;
1614
import org.hibernate.type.descriptor.jdbc.JdbcType;
@@ -77,21 +75,6 @@ public <X> BasicType<X> resolveIndicatedType(JdbcTypeIndicators indicators, Java
7775
return (BasicType<X>) this;
7876
}
7977

80-
@Override
81-
public Object disassemble(Object value, SharedSessionContractImplementor session) {
82-
if ( value == null ) {
83-
return null;
84-
}
85-
if ( baseDescriptor.isInstance( (E) value ) ) {
86-
// Support binding a single element as parameter value
87-
final BasicCollectionJavaType<C, E> javaType = (BasicCollectionJavaType<C, E>) getJavaTypeDescriptor();
88-
final C collection = javaType.getSemantics().instantiateRaw( 1, null );
89-
collection.add( (E) value );
90-
return collection;
91-
}
92-
return value;
93-
}
94-
9578
@Override
9679
public boolean equals(Object o) {
9780
return o == this || o.getClass() == BasicCollectionType.class

hibernate-core/src/main/java/org/hibernate/type/ConvertedBasicArrayType.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@
66
*/
77
package org.hibernate.type;
88

9-
import java.lang.reflect.Array;
109
import java.util.Objects;
1110

12-
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1311
import org.hibernate.type.descriptor.ValueBinder;
1412
import org.hibernate.type.descriptor.ValueExtractor;
1513
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
@@ -78,20 +76,6 @@ public <X> BasicType<X> resolveIndicatedType(JdbcTypeIndicators indicators, Java
7876
return (BasicType<X>) this;
7977
}
8078

81-
@Override
82-
public Object disassemble(Object value, SharedSessionContractImplementor session) {
83-
if ( value == null ) {
84-
return null;
85-
}
86-
if ( baseDescriptor.isInstance( (E) value ) ) {
87-
// Support binding a single element as parameter value
88-
final Object array = Array.newInstance( baseDescriptor.getJavaType(), 1 );
89-
Array.set( array, 0, value );
90-
return array;
91-
}
92-
return value;
93-
}
94-
9579
@Override
9680
public BasicValueConverter<T, ?> getValueConverter() {
9781
return converter;

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ArrayJavaType.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,14 @@ else if ( value instanceof BinaryStream ) {
320320
// When the value is a BinaryStream, this is a deserialization request
321321
return fromBytes( ( (BinaryStream) value ).getBytes() );
322322
}
323+
else if ( getElementJavaType().isInstance( value ) ) {
324+
// Support binding a single element as parameter value
325+
//noinspection unchecked
326+
final T[] wrapped = (T[]) java.lang.reflect.Array.newInstance( getElementJavaType().getJavaTypeClass(), 1 );
327+
//noinspection unchecked
328+
wrapped[0] = (T) value;
329+
return wrapped;
330+
}
323331

324332
throw unknownWrap( value.getClass() );
325333
}

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BooleanPrimitiveArrayJavaType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ else if ( value.getClass().isArray() ) {
168168
}
169169
return wrapped;
170170
}
171+
else if ( value instanceof Boolean ) {
172+
// Support binding a single element as parameter value
173+
return new boolean[]{ (boolean) value };
174+
}
171175

172176
throw unknownWrap( value.getClass() );
173177
}

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DoublePrimitiveArrayJavaType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ else if ( value.getClass().isArray() ) {
168168
}
169169
return wrapped;
170170
}
171+
else if ( value instanceof Double ) {
172+
// Support binding a single element as parameter value
173+
return new double[]{ (double) value };
174+
}
171175

172176
throw unknownWrap( value.getClass() );
173177
}

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/FloatPrimitiveArrayJavaType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ else if ( value.getClass().isArray() ) {
168168
}
169169
return wrapped;
170170
}
171+
else if ( value instanceof Float ) {
172+
// Support binding a single element as parameter value
173+
return new float[]{ (float) value };
174+
}
171175

172176
throw unknownWrap( value.getClass() );
173177
}

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/IntegerPrimitiveArrayJavaType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ else if ( value.getClass().isArray() ) {
168168
}
169169
return wrapped;
170170
}
171+
else if ( value instanceof Integer ) {
172+
// Support binding a single element as parameter value
173+
return new int[]{ (int) value };
174+
}
171175

172176
throw unknownWrap( value.getClass() );
173177
}

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/LongPrimitiveArrayJavaType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ else if ( value.getClass().isArray() ) {
168168
}
169169
return wrapped;
170170
}
171+
else if ( value instanceof Long ) {
172+
// Support binding a single element as parameter value
173+
return new long[]{ (long) value };
174+
}
171175

172176
throw unknownWrap( value.getClass() );
173177
}

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveByteArrayJavaType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ public <X> byte[] wrap(X value, WrapperOptions options) {
136136
throw new HibernateException( "Unable to access lob stream", e );
137137
}
138138
}
139+
else if ( value instanceof Byte ) {
140+
// Support binding a single element as parameter value
141+
return new byte[]{ (byte) value };
142+
}
139143

140144
throw unknownWrap( value.getClass() );
141145
}

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveCharacterArrayJavaType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ public <X> char[] wrap(X value, WrapperOptions options) {
9090
if (value instanceof Reader) {
9191
return DataHelper.extractString( ( (Reader) value ) ).toCharArray();
9292
}
93+
else if ( value instanceof Character ) {
94+
// Support binding a single element as parameter value
95+
return new char[]{ (char) value };
96+
}
9397
throw unknownWrap( value.getClass() );
9498
}
9599

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ShortPrimitiveArrayJavaType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ else if ( value.getClass().isArray() ) {
168168
}
169169
return wrapped;
170170
}
171+
else if ( value instanceof Short ) {
172+
// Support binding a single element as parameter value
173+
return new short[]{ (short) value };
174+
}
171175

172176
throw unknownWrap( value.getClass() );
173177
}

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/BasicCollectionJavaType.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,13 @@ else if ( value.getClass().isArray() ) {
463463
}
464464
return wrapped;
465465
}
466+
else if ( getElementJavaType().isInstance( value ) ) {
467+
// Support binding a single element as parameter value
468+
final C wrapped = semantics.instantiateRaw( 1, null );
469+
//noinspection unchecked
470+
wrapped.add( (E) value );
471+
return wrapped;
472+
}
466473

467474
throw unknownWrap( value.getClass() );
468475
}

hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayConstructorTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,10 @@ public void testEmpty(SessionFactoryScope scope) {
7070
@Test
7171
public void testNonExisting(SessionFactoryScope scope) {
7272
scope.inSession( em -> {
73+
//tag::hql-array-example[]
7374
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where e.theArray = array('abc')", EntityWithArrays.class )
7475
.getResultList();
76+
//end::hql-array-example[]
7577
assertEquals( 0, results.size() );
7678
} );
7779
}

hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/CriteriaToBigDecimalTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,35 @@ public void testToBigDecimal2(EntityManagerFactoryScope scope) {
101101
);
102102
}
103103

104+
@Test
105+
public void testToBigDecimal3(EntityManagerFactoryScope scope) {
106+
scope.inTransaction(
107+
entityManager -> {
108+
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
109+
final CriteriaQuery<Object> query = criteriaBuilder.createQuery();
110+
final Root<Person> person = query.from( Person.class );
111+
query.select( criteriaBuilder.sum( person.get( "ageAsBigDecimal" ), 1 ) );
112+
113+
BigDecimal result = (BigDecimal) entityManager.createQuery( query ).getSingleResult();
114+
115+
assertEquals( new BigDecimal( "21" ), result.stripTrailingZeros() );
116+
}
117+
);
118+
}
119+
120+
@Test
121+
public void testToBigDecimal4(EntityManagerFactoryScope scope) {
122+
scope.inTransaction(
123+
entityManager -> {
124+
BigDecimal result = (BigDecimal) entityManager.createQuery( "select p.ageAsBigDecimal + :val from Person p" )
125+
.setParameter( "val", 1 )
126+
.getSingleResult();
127+
128+
assertEquals( new BigDecimal( "21" ), result.stripTrailingZeros() );
129+
}
130+
);
131+
}
132+
104133
@Entity(name = "Person")
105134
public static class Person {
106135
@Id
@@ -109,6 +138,7 @@ public static class Person {
109138
private String name;
110139

111140
private Integer age;
141+
private BigDecimal ageAsBigDecimal;
112142

113143
Person() {
114144
}
@@ -117,6 +147,7 @@ public Person(Integer id, String name, Integer age) {
117147
this.id = id;
118148
this.name = name;
119149
this.age = age;
150+
this.ageAsBigDecimal = new BigDecimal( age );
120151
}
121152
}
122153
}

0 commit comments

Comments
 (0)