improve error reporting in DynamicInstantiation stuff

This commit is contained in:
Gavin 2023-05-20 10:26:00 +02:00 committed by Gavin King
parent 4c489eedbd
commit addd88000c
3 changed files with 68 additions and 71 deletions

View File

@ -39,9 +39,7 @@ public class DynamicInstantiationAssemblerConstructorImpl<R> implements DomainRe
} }
@Override @Override
public R assemble( public R assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
RowProcessingState rowProcessingState,
JdbcValuesSourceProcessingOptions options) {
final int numberOfArgs = argumentReaders.size(); final int numberOfArgs = argumentReaders.size();
Object[] args = new Object[ numberOfArgs ]; Object[] args = new Object[ numberOfArgs ];
for ( int i = 0; i < numberOfArgs; i++ ) { for ( int i = 0; i < numberOfArgs; i++ ) {
@ -52,10 +50,12 @@ public class DynamicInstantiationAssemblerConstructorImpl<R> implements DomainRe
return targetConstructor.newInstance( args ); return targetConstructor.newInstance( args );
} }
catch (InvocationTargetException e) { catch (InvocationTargetException e) {
throw new InstantiationException( "Error performing dynamic instantiation : " + targetConstructor.getDeclaringClass().getName(), e.getCause() ); throw new InstantiationException( "Error instantiating class '"
+ targetConstructor.getDeclaringClass().getName() + "'", e.getCause() );
} }
catch (Exception e) { catch (Exception e) {
throw new InstantiationException( "Error performing dynamic instantiation : " + targetConstructor.getDeclaringClass().getName(), e ); throw new InstantiationException( "Error instantiating class '"
+ targetConstructor.getDeclaringClass().getName() + "'", e );
} }
} }
} }

View File

@ -78,8 +78,8 @@ public class DynamicInstantiationAssemblerInjectionImpl<T> implements DomainResu
} }
else { else {
throw new InstantiationException( throw new InstantiationException(
"Unable to determine dynamic instantiation injection strategy for " + "Cannot set field '" + argumentReader.getAlias()
targetJavaType.getName() + "#" + argumentReader.getAlias() + "' to instantiate '" + targetJavaType.getName() + "'"
); );
} }
} }
@ -114,8 +114,14 @@ public class DynamicInstantiationAssemblerInjectionImpl<T> implements DomainResu
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public T assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) { public T assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
final T result;
try { try {
final T result = target.getJavaTypeClass().newInstance(); result = target.getJavaTypeClass().newInstance();
}
catch (IllegalAccessException | InstantiationException | java.lang.InstantiationException e) {
throw new InstantiationException( "Error instantiating class '"
+ target.getJavaType().getTypeName() + "' using default constructor", e );
}
for ( BeanInjection beanInjection : beanInjections ) { for ( BeanInjection beanInjection : beanInjections ) {
beanInjection.getBeanInjector().inject( beanInjection.getBeanInjector().inject(
result, result,
@ -124,8 +130,4 @@ public class DynamicInstantiationAssemblerInjectionImpl<T> implements DomainResu
} }
return result; return result;
} }
catch (IllegalAccessException | InstantiationException | java.lang.InstantiationException e) {
throw new InstantiationException( "Could not call default constructor [" + target.getJavaType().getTypeName() + "]", e );
}
}
} }

View File

@ -16,7 +16,6 @@ import java.util.Set;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.query.sqm.DynamicInstantiationNature; import org.hibernate.query.sqm.DynamicInstantiationNature;
import org.hibernate.query.sqm.tree.expression.Compatibility;
import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.FetchParentAccess;
@ -25,6 +24,9 @@ import org.hibernate.type.descriptor.java.JavaType;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import static java.util.stream.Collectors.toList;
import static org.hibernate.query.sqm.tree.expression.Compatibility.areAssignmentCompatible;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -90,16 +92,15 @@ public class DynamicInstantiationResultImpl<R> implements DynamicInstantiationRe
else { else {
if ( !aliases.add( argumentAlias ) ) { if ( !aliases.add( argumentAlias ) ) {
duplicatedAliases.add( argumentAlias ); duplicatedAliases.add( argumentAlias );
log.debugf( "Query defined duplicate resultVariable encountered multiple declarations of [%s]", log.debugf(
"Query defined duplicate resultVariable encountered multiple declarations of [%s]",
argumentAlias argumentAlias
); );
} }
areAnyArgumentsAliased = true; areAnyArgumentsAliased = true;
} }
argumentReaders.add( argumentReaders.add( argumentResult.createResultAssembler( parentAccess, creationState ) );
argumentResult.createResultAssembler( parentAccess, creationState )
);
} }
} }
@ -124,34 +125,28 @@ public class DynamicInstantiationResultImpl<R> implements DynamicInstantiationRe
if ( log.isDebugEnabled() && areAnyArgumentsAliased ) { if ( log.isDebugEnabled() && areAnyArgumentsAliased ) {
log.debug( "One or more arguments for List dynamic instantiation (`new list(...)`) specified an alias; ignoring" ); log.debug( "One or more arguments for List dynamic instantiation (`new list(...)`) specified an alias; ignoring" );
} }
return (DomainResultAssembler<R>) new DynamicInstantiationAssemblerListImpl( return (DomainResultAssembler<R>)
(JavaType<List<?>>) javaType, new DynamicInstantiationAssemblerListImpl( (JavaType<List<?>>) javaType, argumentReaders );
argumentReaders
);
} }
else if ( nature == DynamicInstantiationNature.MAP ) { else if ( nature == DynamicInstantiationNature.MAP ) {
if ( ! areAllArgumentsAliased ) { if ( ! areAllArgumentsAliased ) {
throw new IllegalStateException( "Map dynamic instantiation contained one or more arguments with no alias" ); throw new IllegalStateException( "Map instantiation contained one or more arguments with no alias" );
} }
if ( !duplicatedAliases.isEmpty() ) { if ( !duplicatedAliases.isEmpty() ) {
throw new IllegalStateException( throw new IllegalStateException(
"Map dynamic instantiation contained arguments with duplicated aliases [" + StringHelper.join( ",", duplicatedAliases ) + "]" "Map instantiation has arguments with duplicate aliases ["
+ StringHelper.join( ",", duplicatedAliases ) + "]"
); );
} }
return (DomainResultAssembler<R>) new DynamicInstantiationAssemblerMapImpl( return (DomainResultAssembler<R>)
(JavaType<Map<?,?>>) javaType, new DynamicInstantiationAssemblerMapImpl( (JavaType<Map<?,?>>) javaType, argumentReaders );
argumentReaders
);
} }
else { else {
// find a constructor matching argument types // find a constructor matching argument types
constructor_loop: constructor_loop:
for ( Constructor<?> constructor : javaType.getJavaTypeClass().getDeclaredConstructors() ) { for ( Constructor<?> constructor : javaType.getJavaTypeClass().getDeclaredConstructors() ) {
final Type[] genericParameterTypes = constructor.getGenericParameterTypes(); final Type[] genericParameterTypes = constructor.getGenericParameterTypes();
if ( genericParameterTypes.length != argumentReaders.size() ) { if ( genericParameterTypes.length == argumentReaders.size() ) {
continue;
}
for ( int i = 0; i < argumentReaders.size(); i++ ) { for ( int i = 0; i < argumentReaders.size(); i++ ) {
final ArgumentReader<?> argumentReader = argumentReaders.get( i ); final ArgumentReader<?> argumentReader = argumentReaders.get( i );
final JavaType<?> argumentTypeDescriptor = creationState.getSqlAstCreationContext() final JavaType<?> argumentTypeDescriptor = creationState.getSqlAstCreationContext()
@ -160,11 +155,7 @@ public class DynamicInstantiationResultImpl<R> implements DynamicInstantiationRe
.getJavaTypeRegistry() .getJavaTypeRegistry()
.resolveDescriptor( genericParameterTypes[i] ); .resolveDescriptor( genericParameterTypes[i] );
final boolean assignmentCompatible = Compatibility.areAssignmentCompatible( if ( !areAssignmentCompatible( argumentTypeDescriptor, argumentReader.getAssembledJavaType() ) ) {
argumentTypeDescriptor,
argumentReader.getAssembledJavaType()
);
if ( !assignmentCompatible ) {
if ( log.isDebugEnabled() ) { if ( log.isDebugEnabled() ) {
log.debugf( log.debugf(
"Skipping constructor for dynamic-instantiation match due to argument mismatch [%s] : %s -> %s", "Skipping constructor for dynamic-instantiation match due to argument mismatch [%s] : %s -> %s",
@ -179,11 +170,8 @@ public class DynamicInstantiationResultImpl<R> implements DynamicInstantiationRe
constructor.setAccessible( true ); constructor.setAccessible( true );
//noinspection rawtypes //noinspection rawtypes
return new DynamicInstantiationAssemblerConstructorImpl( return new DynamicInstantiationAssemblerConstructorImpl( constructor, javaType, argumentReaders );
constructor, }
javaType,
argumentReaders
);
} }
if ( log.isDebugEnabled() ) { if ( log.isDebugEnabled() ) {
@ -195,20 +183,27 @@ public class DynamicInstantiationResultImpl<R> implements DynamicInstantiationRe
if ( ! areAllArgumentsAliased ) { if ( ! areAllArgumentsAliased ) {
throw new IllegalStateException( throw new IllegalStateException(
"Could not determine appropriate instantiation strategy - no matching constructor found and one or more arguments did not define alias for bean-injection" "Cannot instantiate class '" + javaType.getJavaType().getTypeName() + "'"
+ " (it has no constructor with signature " + signature()
+ ", and not every argument has an alias)"
); );
} }
if ( !duplicatedAliases.isEmpty() ) { if ( !duplicatedAliases.isEmpty() ) {
throw new IllegalStateException( throw new IllegalStateException(
"Could not determine appropriate instantiation strategy - no matching constructor found and arguments defined duplicated aliases [" + "Cannot instantiate class '" + javaType.getJavaType().getTypeName() + "'"
StringHelper.join( ",", duplicatedAliases ) + "] for bean-injection" + " (it has no constructor with signature " + signature()
+ ", and has arguments with duplicate aliases ["
+ StringHelper.join( ",", duplicatedAliases ) + "])"
); );
} }
return new DynamicInstantiationAssemblerInjectionImpl<>( return new DynamicInstantiationAssemblerInjectionImpl<>( javaType, argumentReaders );
javaType,
argumentReaders
);
} }
} }
private List<String> signature() {
return argumentResults.stream()
.map( adt -> adt.getResultJavaType().getJavaType().getTypeName() )
.collect( toList() );
}
} }