|
5 | 5 | package org.hibernate.query.sql.internal;
|
6 | 6 |
|
7 | 7 | import java.io.Serializable;
|
8 |
| -import java.lang.reflect.Constructor; |
9 | 8 | import java.time.Instant;
|
10 | 9 | import java.util.Calendar;
|
11 | 10 | import java.util.Collection;
|
@@ -355,32 +354,43 @@ private void checkResultType(Class<R> resultType, ResultSetMapping resultSetMapp
|
355 | 354 | }
|
356 | 355 | break;
|
357 | 356 | default:
|
358 |
| - // The return type has to be a class with an appropriate constructor, i.e. one whose parameter types match |
359 |
| - // the types of the result builders. If none such constructor is found, throw an IAE |
| 357 | + // The return type has to be a class with an appropriate constructor, |
| 358 | + // i.e. one whose parameter types match the types of the result builders. |
| 359 | + // If no such constructor is found, throw an IAE |
360 | 360 | if ( !validConstructorFoundForResultType( resultType, resultSetMapping ) ) {
|
361 |
| - throw new IllegalArgumentException( "The declared return type for a multi-valued result set mapping should be Object[], Map, List, or Tuple" ); |
| 361 | + throw new IllegalArgumentException( |
| 362 | + "The return type for a multivalued result set mapping should be Object[], Map, List, or Tuple" |
| 363 | + + " or it must have an appropriate constructor" |
| 364 | + ); |
362 | 365 | }
|
363 | 366 | }
|
364 | 367 | }
|
365 | 368 | }
|
366 | 369 |
|
367 | 370 | private boolean validConstructorFoundForResultType(Class<R> resultType, ResultSetMapping resultSetMapping) {
|
368 |
| - // Only 1 constructor with the right number of parameters is allowed (see NativeQueryConstructorTransformer) |
369 |
| - Constructor<?> constructor = resultType.getConstructors()[0]; |
370 |
| - if ( constructor.getParameterCount() != resultSetMapping.getNumberOfResultBuilders() ) { |
371 |
| - return false; |
372 |
| - } |
373 |
| - final List<ResultBuilder> resultBuilders = resultSetMapping.getResultBuilders(); |
374 |
| - Class<?>[] paramTypes = constructor.getParameterTypes(); |
375 |
| - for ( int i = 0; i < resultBuilders.size(); i++ ) { |
376 |
| - if ( |
377 |
| - resultBuilders.get( i ).getJavaType() != ( paramTypes[i].isPrimitive() ? |
378 |
| - getDescriptorByPrimitiveType(paramTypes[i] ).getWrapperClass() : |
379 |
| - paramTypes[i]) ) { |
380 |
| - return false; |
| 371 | + // TODO: Only one constructor with the right number of parameters is allowed |
| 372 | + // (see NativeQueryConstructorTransformer) so we should validate that |
| 373 | + outer: for ( var constructor : resultType.getConstructors() ) { |
| 374 | + if ( constructor.getParameterCount() == resultSetMapping.getNumberOfResultBuilders() ) { |
| 375 | + final var resultBuilders = resultSetMapping.getResultBuilders(); |
| 376 | + final var paramTypes = constructor.getParameterTypes(); |
| 377 | + for ( int i = 0; i < resultBuilders.size(); i++ ) { |
| 378 | + if ( !constructorParameterMatches( resultBuilders.get( i ), paramTypes[i] ) ) { |
| 379 | + continue outer; |
| 380 | + } |
| 381 | + } |
| 382 | + return true; |
381 | 383 | }
|
382 | 384 | }
|
383 |
| - return true; |
| 385 | + return false; |
| 386 | + } |
| 387 | + |
| 388 | + private static boolean constructorParameterMatches(ResultBuilder resultBuilder, Class<?> paramType) { |
| 389 | + final Class<?> parameterClass = |
| 390 | + paramType.isPrimitive() |
| 391 | + ? getDescriptorByPrimitiveType( paramType ).getWrapperClass() |
| 392 | + : paramType; |
| 393 | + return resultBuilder.getJavaType() == parameterClass; |
384 | 394 | }
|
385 | 395 |
|
386 | 396 | protected <T> void setTupleTransformerForResultType(Class<T> resultClass) {
|
|
0 commit comments