Skip to content

Commit c5db0d3

Browse files
committed
HHH-18664 Consistent constructor matching logic for row-transformer
1 parent fc38d88 commit c5db0d3

File tree

4 files changed

+48
-59
lines changed

4 files changed

+48
-59
lines changed

hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ConcreteSqmSelectQueryPlan.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,11 @@ else if ( Map.class.equals( resultType ) ) {
287287
}
288288
else if ( isClass( resultType ) ) {
289289
try {
290-
return new RowTransformerConstructorImpl<>( resultType, tupleMetadata );
290+
return new RowTransformerConstructorImpl<>(
291+
resultType,
292+
tupleMetadata,
293+
sqm.nodeBuilder().getTypeConfiguration()
294+
);
291295
}
292296
catch (InstantiationException ie) {
293297
return new RowTransformerCheckingImpl<>( resultType );
@@ -310,7 +314,11 @@ else if ( Map.class.equals( resultType ) ) {
310314
return (RowTransformer<T>) new RowTransformerMapImpl( tupleMetadata );
311315
}
312316
else if ( isClass( resultType ) ) {
313-
return new RowTransformerConstructorImpl<>( resultType, tupleMetadata );
317+
return new RowTransformerConstructorImpl<>(
318+
resultType,
319+
tupleMetadata,
320+
sqm.nodeBuilder().getTypeConfiguration()
321+
);
314322
}
315323
else {
316324
throw new QueryTypeMismatchException( "Result type '" + resultType.getSimpleName()

hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/DynamicInstantiationResultImpl.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
import org.hibernate.sql.results.graph.InitializerParent;
2020
import org.hibernate.sql.results.graph.instantiation.DynamicInstantiationResult;
2121
import org.hibernate.type.descriptor.java.JavaType;
22-
2322
import org.hibernate.type.spi.TypeConfiguration;
23+
2424
import org.jboss.logging.Logger;
2525

2626
import static java.util.stream.Collectors.toList;
27-
import static org.hibernate.sql.results.graph.instantiation.internal.InstantiationHelper.isConstructorCompatible;
27+
import static org.hibernate.sql.results.graph.instantiation.internal.InstantiationHelper.findMatchingConstructor;
2828

2929
/**
3030
* @author Steve Ebersole
@@ -164,13 +164,14 @@ private DomainResultAssembler<R> assembler(
164164
.getMappingMetamodel()
165165
.getTypeConfiguration();
166166
// find a constructor matching argument types
167-
for ( Constructor<?> constructor : javaType.getJavaTypeClass().getDeclaredConstructors() ) {
168-
if ( isConstructorCompatible( constructor, argumentTypes, typeConfiguration ) ) {
169-
constructor.setAccessible( true );
170-
@SuppressWarnings("unchecked")
171-
final Constructor<R> construct = (Constructor<R>) constructor;
172-
return new DynamicInstantiationAssemblerConstructorImpl<>( construct, javaType, argumentReaders );
173-
}
167+
final Constructor<R> constructor = findMatchingConstructor(
168+
javaType.getJavaTypeClass(),
169+
argumentTypes,
170+
typeConfiguration
171+
);
172+
if ( constructor != null ) {
173+
constructor.setAccessible( true );
174+
return new DynamicInstantiationAssemblerConstructorImpl<>( constructor, javaType, argumentReaders );
174175
}
175176

176177
if ( log.isDebugEnabled() ) {

hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/InstantiationHelper.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,20 @@ private static boolean checkArgument(Class<?> targetJavaType, BeanInfo beanInfo,
5555
}
5656

5757
public static boolean isConstructorCompatible(Class<?> javaClass, List<Class<?>> argTypes, TypeConfiguration typeConfiguration) {
58-
for ( Constructor<?> constructor : javaClass.getDeclaredConstructors() ) {
59-
if ( isConstructorCompatible( constructor, argTypes, typeConfiguration) ) {
60-
return true;
58+
return findMatchingConstructor( javaClass, argTypes, typeConfiguration ) != null;
59+
}
60+
61+
public static <T> Constructor<T> findMatchingConstructor(
62+
Class<T> type,
63+
List<Class<?>> argumentTypes,
64+
TypeConfiguration typeConfiguration) {
65+
for ( final Constructor<?> constructor : type.getDeclaredConstructors() ) {
66+
if ( isConstructorCompatible( constructor, argumentTypes, typeConfiguration ) ) {
67+
//noinspection unchecked
68+
return (Constructor<T>) constructor;
6169
}
6270
}
63-
return false;
71+
return null;
6472
}
6573

6674
public static boolean isConstructorCompatible(

hibernate-core/src/main/java/org/hibernate/sql/results/internal/RowTransformerConstructorImpl.java

Lines changed: 16 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313

1414
import org.hibernate.query.sqm.SqmExpressible;
1515
import org.hibernate.query.sqm.tree.SqmExpressibleAccessor;
16+
import org.hibernate.type.spi.TypeConfiguration;
1617

17-
import static org.hibernate.query.sqm.tree.expression.Compatibility.areAssignmentCompatible;
18+
import static java.util.stream.Collectors.toList;
19+
import static org.hibernate.sql.results.graph.instantiation.internal.InstantiationHelper.findMatchingConstructor;
1820

1921
/**
2022
* {@link RowTransformer} instantiating an arbitrary class
@@ -25,25 +27,25 @@ public class RowTransformerConstructorImpl<T> implements RowTransformer<T> {
2527
private final Class<T> type;
2628
private final Constructor<T> constructor;
2729

28-
public RowTransformerConstructorImpl(Class<T> type, TupleMetadata tupleMetadata) {
30+
public RowTransformerConstructorImpl(
31+
Class<T> type,
32+
TupleMetadata tupleMetadata,
33+
TypeConfiguration typeConfiguration) {
2934
this.type = type;
3035
final List<TupleElement<?>> elements = tupleMetadata.getList();
31-
final Class<?>[] sig = new Class[elements.size()];
32-
for (int i = 0; i < elements.size(); i++) {
33-
sig[i] = resolveElementJavaType( elements.get( i ) );
34-
}
35-
if ( sig.length == 1 && sig[0] == null ) {
36+
final List<Class<?>> argumentTypes = elements.stream()
37+
.map( RowTransformerConstructorImpl::resolveElementJavaType )
38+
.collect( toList() );
39+
if ( argumentTypes.size() == 1 && argumentTypes.get( 0 ) == null ) {
3640
// Can not (properly) resolve constructor for single null element
3741
throw new InstantiationException( "Cannot instantiate query result type, argument types are unknown ", type );
3842
}
39-
try {
40-
constructor = findMatchingConstructor( type, sig );
41-
constructor.setAccessible( true );
42-
}
43-
catch (Exception e) {
44-
//TODO try again with primitive types
45-
throw new InstantiationException( "Cannot instantiate query result type ", type, e );
43+
44+
constructor = findMatchingConstructor( type, argumentTypes, typeConfiguration );
45+
if ( constructor == null ) {
46+
throw new InstantiationException( "Cannot instantiate query result type, found no matching constructor", type );
4647
}
48+
constructor.setAccessible( true );
4749
}
4850

4951
private static Class<?> resolveElementJavaType(TupleElement<?> element) {
@@ -57,36 +59,6 @@ private static Class<?> resolveElementJavaType(TupleElement<?> element) {
5759
return element.getJavaType();
5860
}
5961

60-
private Constructor<T> findMatchingConstructor(Class<T> type, Class<?>[] sig) throws Exception {
61-
try {
62-
return type.getDeclaredConstructor( sig );
63-
}
64-
catch (NoSuchMethodException | SecurityException e) {
65-
constructor_loop:
66-
for ( final Constructor<?> constructor : type.getDeclaredConstructors() ) {
67-
final Class<?>[] parameterTypes = constructor.getParameterTypes();
68-
if ( parameterTypes.length == sig.length ) {
69-
for ( int i = 0; i < sig.length; i++ ) {
70-
final Class<?> parameterType = parameterTypes[i];
71-
final Class<?> argType = sig[i];
72-
final boolean assignmentCompatible;
73-
assignmentCompatible =
74-
argType == null && !parameterType.isPrimitive()
75-
|| areAssignmentCompatible(
76-
parameterType,
77-
argType
78-
);
79-
if ( !assignmentCompatible ) {
80-
continue constructor_loop;
81-
}
82-
}
83-
return (Constructor<T>) constructor;
84-
}
85-
}
86-
throw e;
87-
}
88-
}
89-
9062
@Override
9163
public T transformRow(Object[] row) {
9264
try {

0 commit comments

Comments
 (0)