HHH-16564 allow null in 'select new' argument list

This commit is contained in:
Gavin 2023-05-06 22:22:58 +02:00 committed by Gavin King
parent 7eacbfab3c
commit c922a10df2
3 changed files with 49 additions and 2 deletions

View File

@ -391,10 +391,13 @@
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.JavaObjectType; import org.hibernate.type.JavaObjectType;
import org.hibernate.type.SqlTypes; import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.AbstractClassJavaType;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.JavaTypeHelper; import org.hibernate.type.descriptor.java.JavaTypeHelper;
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
import org.hibernate.type.descriptor.jdbc.NullJdbcType;
import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.internal.BasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.UserVersionType; import org.hibernate.usertype.UserVersionType;
@ -4872,8 +4875,17 @@ public Expression visitLiteral(SqmLiteral<?> literal) {
} }
final MappingModelExpressible<?> keyExpressible = getKeyExpressible( mappingModelExpressible ); final MappingModelExpressible<?> keyExpressible = getKeyExpressible( mappingModelExpressible );
if ( keyExpressible == null ) { if ( keyExpressible == null ) {
// Default to the Object type // treat Void as the bottom type, the class of null
return new QueryLiteral<>( null, basicType( Object.class ) ); return new QueryLiteral<>( null, new JavaObjectType(NullJdbcType.INSTANCE, new AbstractClassJavaType<>(Void.class) {
@Override
public <X> X unwrap(Object value, Class<X> type, WrapperOptions options) {
return null;
}
@Override
public <X> Void wrap(X value, WrapperOptions options) {
return null;
}
} ) );
} }
final List<Expression> expressions = new ArrayList<>( keyExpressible.getJdbcTypeCount() ); final List<Expression> expressions = new ArrayList<>( keyExpressible.getJdbcTypeCount() );

View File

@ -57,6 +57,11 @@ public static boolean areAssignmentCompatible(Class to, Class from) {
assert to != null; assert to != null;
assert from != null; assert from != null;
if ( from == Void.class ) {
// treat Void as the bottom type, the class of null
return true;
}
if ( to.isAssignableFrom( from ) ) { if ( to.isAssignableFrom( from ) ) {
return true; return true;
} }

View File

@ -61,6 +61,36 @@ public void testSelectNewCastNull(SessionFactoryScope scope) {
); );
} }
@Test
@TestForIssue(jiraKey = "HHH-16564")
public void testSelectNewNull(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> {
Person result = (Person) session.createQuery(
"select new Person( id, firstName, null, lastName ) from Person where lastName='Munster'"
).uniqueResult();
assertEquals( "Herman", result.firstName );
assertNull( result.middleName );
assertEquals( "Munster", result.lastName );
}
);
}
@Test
@TestForIssue(jiraKey = "HHH-16564")
public void testSelectNull(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> {
Object[] result = (Object[]) session.createQuery(
"select id, firstName, null, lastName from Person where lastName='Munster'"
).uniqueResult();
assertEquals( "Herman", result[1] );
assertNull( result[2] );
assertEquals( "Munster", result[3] );
}
);
}
@BeforeEach @BeforeEach
public void createTestData(SessionFactoryScope scope) { public void createTestData(SessionFactoryScope scope) {
scope.inTransaction( scope.inTransaction(