HHH-17729 move validation of constructors in HQL instantiations to SemanticQueryBuilder

report SemanticExceptions with the query string
fix some warnings in ReflectHelper
This commit is contained in:
Gavin King 2024-02-11 13:40:51 +01:00
parent 0bce456e3a
commit 24937b4e67
15 changed files with 337 additions and 254 deletions

View File

@ -9,14 +9,13 @@ package org.hibernate.boot.model;
import org.hibernate.InstantiationException; import org.hibernate.InstantiationException;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.resource.beans.spi.BeanInstanceProducer; import org.hibernate.resource.beans.spi.BeanInstanceProducer;
import org.hibernate.type.spi.TypeBootstrapContext; import org.hibernate.type.spi.TypeBootstrapContext;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.Map; import java.util.Map;
import static org.hibernate.internal.util.ReflectHelper.getConstructor;
/** /**
* {@link BeanInstanceProducer} implementation for building beans related to custom types. * {@link BeanInstanceProducer} implementation for building beans related to custom types.
* *
@ -33,7 +32,7 @@ public class TypeBeanInstanceProducer implements BeanInstanceProducer, TypeBoots
@Override @Override
public <B> B produceBeanInstance(Class<B> beanType) { public <B> B produceBeanInstance(Class<B> beanType) {
final Constructor<B> bootstrapContextAwareConstructor = final Constructor<B> bootstrapContextAwareConstructor =
getConstructor( beanType, TypeBootstrapContext.class ); ReflectHelper.getConstructorOrNull( beanType, TypeBootstrapContext.class );
if ( bootstrapContextAwareConstructor != null ) { if ( bootstrapContextAwareConstructor != null ) {
try { try {
return bootstrapContextAwareConstructor.newInstance( this ); return bootstrapContextAwareConstructor.newInstance( this );
@ -43,7 +42,7 @@ public class TypeBeanInstanceProducer implements BeanInstanceProducer, TypeBoots
} }
} }
else { else {
final Constructor<B> constructor = getConstructor( beanType ); final Constructor<B> constructor = ReflectHelper.getConstructorOrNull( beanType );
if ( constructor != null ) { if ( constructor != null ) {
try { try {
return constructor.newInstance(); return constructor.newInstance();

View File

@ -27,8 +27,8 @@ public class CustomOptimizerDescriptor implements OptimizerDescriptor {
return className; return className;
} }
@Override @Override @SuppressWarnings("unchecked")
public Class<? extends Optimizer> getOptimizerClass() throws ClassNotFoundException { public Class<? extends Optimizer> getOptimizerClass() throws ClassNotFoundException {
return ReflectHelper.classForName( className ); return (Class<? extends Optimizer>) ReflectHelper.classForName( className );
} }
} }

View File

@ -42,9 +42,9 @@ import jakarta.persistence.Transient;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class ReflectHelper { public final class ReflectHelper {
public static final Class[] NO_PARAM_SIGNATURE = ArrayHelper.EMPTY_CLASS_ARRAY; public static final Class<?>[] NO_PARAM_SIGNATURE = ArrayHelper.EMPTY_CLASS_ARRAY;
public static final Class[] SINGLE_OBJECT_PARAM_SIGNATURE = new Class[] { Object.class }; public static final Class<?>[] SINGLE_OBJECT_PARAM_SIGNATURE = new Class[] { Object.class };
private static final Method OBJECT_EQUALS; private static final Method OBJECT_EQUALS;
private static final Method OBJECT_HASHCODE; private static final Method OBJECT_HASHCODE;
@ -99,7 +99,7 @@ public final class ReflectHelper {
* @return The equals method reference * @return The equals method reference
* @throws NoSuchMethodException Should indicate an attempt to extract equals method from interface. * @throws NoSuchMethodException Should indicate an attempt to extract equals method from interface.
*/ */
public static Method extractEqualsMethod(Class clazz) throws NoSuchMethodException { public static Method extractEqualsMethod(Class<?> clazz) throws NoSuchMethodException {
return clazz.getMethod( "equals", SINGLE_OBJECT_PARAM_SIGNATURE ); return clazz.getMethod( "equals", SINGLE_OBJECT_PARAM_SIGNATURE );
} }
@ -110,7 +110,7 @@ public final class ReflectHelper {
* @return The hashCode method reference * @return The hashCode method reference
* @throws NoSuchMethodException Should indicate an attempt to extract hashCode method from interface. * @throws NoSuchMethodException Should indicate an attempt to extract hashCode method from interface.
*/ */
public static Method extractHashCodeMethod(Class clazz) throws NoSuchMethodException { public static Method extractHashCodeMethod(Class<?> clazz) throws NoSuchMethodException {
return clazz.getMethod( "hashCode", NO_PARAM_SIGNATURE ); return clazz.getMethod( "hashCode", NO_PARAM_SIGNATURE );
} }
@ -120,7 +120,7 @@ public final class ReflectHelper {
* @param clazz The class to check * @param clazz The class to check
* @return True if clazz defines an equals override. * @return True if clazz defines an equals override.
*/ */
public static boolean overridesEquals(Class clazz) { public static boolean overridesEquals(Class<?> clazz) {
Method equals; Method equals;
try { try {
equals = extractEqualsMethod( clazz ); equals = extractEqualsMethod( clazz );
@ -137,7 +137,7 @@ public final class ReflectHelper {
* @param clazz The class to check * @param clazz The class to check
* @return True if clazz defines an hashCode override. * @return True if clazz defines an hashCode override.
*/ */
public static boolean overridesHashCode(Class clazz) { public static boolean overridesHashCode(Class<?> clazz) {
Method hashCode; Method hashCode;
try { try {
hashCode = extractHashCodeMethod( clazz ); hashCode = extractHashCodeMethod( clazz );
@ -155,7 +155,7 @@ public final class ReflectHelper {
* @param intf The interface to check it against. * @param intf The interface to check it against.
* @return True if the class does implement the interface, false otherwise. * @return True if the class does implement the interface, false otherwise.
*/ */
public static boolean implementsInterface(Class clazz, Class intf) { public static boolean implementsInterface(Class<?> clazz, Class<?> intf) {
assert intf.isInterface() : "Interface to check was not an interface"; assert intf.isInterface() : "Interface to check was not an interface";
return intf.isAssignableFrom( clazz ); return intf.isAssignableFrom( clazz );
} }
@ -171,7 +171,7 @@ public final class ReflectHelper {
* @return The class reference. * @return The class reference.
* @throws ClassNotFoundException From {@link Class#forName(String, boolean, ClassLoader)}. * @throws ClassNotFoundException From {@link Class#forName(String, boolean, ClassLoader)}.
*/ */
public static Class classForName(String name, Class caller) throws ClassNotFoundException { public static Class<?> classForName(String name, Class<?> caller) throws ClassNotFoundException {
try { try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if ( classLoader != null ) { if ( classLoader != null ) {
@ -198,7 +198,7 @@ public final class ReflectHelper {
* or {@link org.hibernate.boot.spi.ClassLoaderAccess} should be preferred * or {@link org.hibernate.boot.spi.ClassLoaderAccess} should be preferred
*/ */
@Deprecated @Deprecated
public static Class classForName(String name) throws ClassNotFoundException { public static Class<?> classForName(String name) throws ClassNotFoundException {
try { try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if ( classLoader != null ) { if ( classLoader != null ) {
@ -217,7 +217,7 @@ public final class ReflectHelper {
* @param member The member. * @param member The member.
* @return True if the member is publicly accessible, false otherwise. * @return True if the member is publicly accessible, false otherwise.
*/ */
public static boolean isPublic(Class clazz, Member member) { public static boolean isPublic(Class<?> clazz, Member member) {
return Modifier.isPublic( member.getModifiers() ) && Modifier.isPublic( clazz.getModifiers() ); return Modifier.isPublic( member.getModifiers() ) && Modifier.isPublic( clazz.getModifiers() );
} }
@ -232,12 +232,12 @@ public final class ReflectHelper {
* *
* @throws MappingException Indicates we were unable to locate the property. * @throws MappingException Indicates we were unable to locate the property.
*/ */
public static Class reflectedPropertyClass( public static Class<?> reflectedPropertyClass(
String className, String className,
String name, String name,
ClassLoaderService classLoaderService) throws MappingException { ClassLoaderService classLoaderService) throws MappingException {
try { try {
Class clazz = classLoaderService.classForName( className ); Class<?> clazz = classLoaderService.classForName( className );
return getter( clazz, name ).getReturnTypeClass(); return getter( clazz, name ).getReturnTypeClass();
} }
catch ( ClassLoadingException e ) { catch ( ClassLoadingException e ) {
@ -266,11 +266,11 @@ public final class ReflectHelper {
* @return The type of the property. * @return The type of the property.
* @throws MappingException Indicates we were unable to locate the property. * @throws MappingException Indicates we were unable to locate the property.
*/ */
public static Class reflectedPropertyClass(Class clazz, String name) throws MappingException { public static Class<?> reflectedPropertyClass(Class<?> clazz, String name) throws MappingException {
return getter( clazz, name ).getReturnTypeClass(); return getter( clazz, name ).getReturnTypeClass();
} }
private static Getter getter(Class clazz, String name) throws MappingException { private static Getter getter(Class<?> clazz, String name) throws MappingException {
return PropertyAccessStrategyMixedImpl.INSTANCE.buildPropertyAccess( clazz, name, true ).getGetter(); return PropertyAccessStrategyMixedImpl.INSTANCE.buildPropertyAccess( clazz, name, true ).getGetter();
} }
@ -304,7 +304,7 @@ public final class ReflectHelper {
* @param clazz The class to check. * @param clazz The class to check.
* @return True if the class is abstract, false otherwise. * @return True if the class is abstract, false otherwise.
*/ */
public static boolean isAbstractClass(Class clazz) { public static boolean isAbstractClass(Class<?> clazz) {
int modifier = clazz.getModifiers(); int modifier = clazz.getModifiers();
return Modifier.isAbstract(modifier) || Modifier.isInterface(modifier); return Modifier.isAbstract(modifier) || Modifier.isInterface(modifier);
} }
@ -315,7 +315,7 @@ public final class ReflectHelper {
* @param clazz The class to check. * @param clazz The class to check.
* @return True if the class is final, false otherwise. * @return True if the class is final, false otherwise.
*/ */
public static boolean isFinalClass(Class clazz) { public static boolean isFinalClass(Class<?> clazz) {
return Modifier.isFinal( clazz.getModifiers() ); return Modifier.isFinal( clazz.getModifiers() );
} }
@ -325,15 +325,19 @@ public final class ReflectHelper {
* *
* @param clazz The class needing instantiation * @param clazz The class needing instantiation
* @param types The types representing the required ctor param signature * @param types The types representing the required ctor param signature
* @return The matching constructor. * @return The matching constructor
* @throws PropertyNotFoundException Indicates we could not locate an appropriate constructor (todo : again with PropertyNotFoundException???) * @throws PropertyNotFoundException Indicates we could not locate an appropriate constructor
*
* @deprecated no longer used, since we moved away from the {@link Type} interface
*/ */
public static Constructor getConstructor(Class clazz, Type[] types) throws PropertyNotFoundException { // todo : again with PropertyNotFoundException???
final Constructor[] candidates = clazz.getConstructors(); @Deprecated(since = "6", forRemoval = true)
Constructor constructor = null; public static Constructor<?> getConstructor(Class<?> clazz, Type[] types) throws PropertyNotFoundException {
final Constructor<?>[] candidates = clazz.getConstructors();
Constructor<?> constructor = null;
int numberOfMatchingConstructors = 0; int numberOfMatchingConstructors = 0;
for ( final Constructor candidate : candidates ) { for ( final Constructor<?> candidate : candidates ) {
final Class[] params = candidate.getParameterTypes(); final Class<?>[] params = candidate.getParameterTypes();
if ( params.length == types.length ) { if ( params.length == types.length ) {
boolean found = true; boolean found = true;
for ( int j = 0; j < params.length; j++ ) { for ( int j = 0; j < params.length; j++ ) {
@ -361,9 +365,18 @@ public final class ReflectHelper {
} }
public static <T> Constructor<T> getConstructor( /**
* Retrieve a constructor for the given class, with arguments matching
* the specified Java {@linkplain Class types}, or return {@code null}
* if no such constructor exists.
*
* @param clazz The class needing instantiation
* @param constructorArgs The types representing the required ctor param signature
* @return The matching constructor, or {@code null}
*/
public static <T> Constructor<T> getConstructorOrNull(
Class<T> clazz, Class<T> clazz,
Class... constructorArgs) { Class<?>... constructorArgs) {
Constructor<T> constructor = null; Constructor<T> constructor = null;
try { try {
constructor = clazz.getDeclaredConstructor( constructorArgs ); constructor = clazz.getDeclaredConstructor( constructorArgs );
@ -380,7 +393,7 @@ public final class ReflectHelper {
return constructor; return constructor;
} }
public static Method getMethod(Class clazz, Method method) { public static Method getMethod(Class<?> clazz, Method method) {
try { try {
return clazz.getMethod( method.getName(), method.getParameterTypes() ); return clazz.getMethod( method.getName(), method.getParameterTypes() );
} }
@ -389,7 +402,7 @@ public final class ReflectHelper {
} }
} }
public static Method getMethod(Class clazz, String methodName, Class... paramTypes) { public static Method getMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
try { try {
return clazz.getMethod( methodName, paramTypes ); return clazz.getMethod( methodName, paramTypes );
} }
@ -398,9 +411,9 @@ public final class ReflectHelper {
} }
} }
public static Field findField(Class containerClass, String propertyName) { public static Field findField(Class<?> containerClass, String propertyName) {
if ( containerClass == null ) { if ( containerClass == null ) {
throw new IllegalArgumentException( "Class on which to find field [" + propertyName + "] cannot be null" ); throw new IllegalArgumentException( "Class<?> on which to find field [" + propertyName + "] cannot be null" );
} }
else if ( containerClass == Object.class ) { else if ( containerClass == Object.class ) {
throw new IllegalArgumentException( "Illegal attempt to locate field [" + propertyName + "] on Object.class" ); throw new IllegalArgumentException( "Illegal attempt to locate field [" + propertyName + "] on Object.class" );
@ -430,7 +443,7 @@ public final class ReflectHelper {
} }
} }
private static Field locateField(Class clazz, String propertyName) { private static Field locateField(Class<?> clazz, String propertyName) {
if ( clazz == null || Object.class.equals( clazz ) ) { if ( clazz == null || Object.class.equals( clazz ) ) {
return null; return null;
} }
@ -451,8 +464,8 @@ public final class ReflectHelper {
return field != null && ( field.getModifiers() & Modifier.STATIC ) == Modifier.STATIC; return field != null && ( field.getModifiers() & Modifier.STATIC ) == Modifier.STATIC;
} }
public static Method findGetterMethod(Class containerClass, String propertyName) { public static Method findGetterMethod(Class<?> containerClass, String propertyName) {
Class checkClass = containerClass; Class<?> checkClass = containerClass;
Method getter = null; Method getter = null;
if ( isRecord( containerClass ) ) { if ( isRecord( containerClass ) ) {
@ -497,10 +510,10 @@ public final class ReflectHelper {
return getter; return getter;
} }
private static Method getGetterOrNull(Class[] interfaces, String propertyName) { private static Method getGetterOrNull(Class<?>[] interfaces, String propertyName) {
Method getter = null; Method getter = null;
for ( int i = 0; getter == null && i < interfaces.length; ++i ) { for ( int i = 0; getter == null && i < interfaces.length; ++i ) {
final Class anInterface = interfaces[i]; final Class<?> anInterface = interfaces[i];
getter = getGetterOrNull( anInterface, propertyName ); getter = getGetterOrNull( anInterface, propertyName );
if ( getter == null ) { if ( getter == null ) {
// if no getter found yet, check all implemented interfaces of interface // if no getter found yet, check all implemented interfaces of interface
@ -513,14 +526,14 @@ public final class ReflectHelper {
/** /**
* Find the method that can be used as the getter for this property. * Find the method that can be used as the getter for this property.
* *
* @param containerClass The Class which contains the property * @param containerClass The Class<?> which contains the property
* @param propertyName The name of the property * @param propertyName The name of the property
* *
* @return The getter method, or {@code null} if there is none. * @return The getter method, or {@code null} if there is none.
* *
* @throws MappingException If the {@code containerClass} has both a get- and an is- form. * @throws MappingException If the {@code containerClass} has both a get- and an is- form.
*/ */
public static Method getGetterOrNull(Class containerClass, String propertyName) { public static Method getGetterOrNull(Class<?> containerClass, String propertyName) {
if ( isRecord( containerClass ) ) { if ( isRecord( containerClass ) ) {
try { try {
return containerClass.getMethod( propertyName, NO_PARAM_SIGNATURE ); return containerClass.getMethod( propertyName, NO_PARAM_SIGNATURE );
@ -583,7 +596,7 @@ public final class ReflectHelper {
String propertyName, String propertyName,
Method getMethod, Method getMethod,
String stemName) { String stemName) {
// verify that the Class does not also define a method with the same stem name with 'is' // verify that the Class<?> does not also define a method with the same stem name with 'is'
try { try {
final Method isMethod = containerClass.getDeclaredMethod( "is" + stemName ); final Method isMethod = containerClass.getDeclaredMethod( "is" + stemName );
if ( !Modifier.isStatic( isMethod.getModifiers() ) && isMethod.getAnnotation( Transient.class ) == null ) { if ( !Modifier.isStatic( isMethod.getModifiers() ) && isMethod.getAnnotation( Transient.class ) == null ) {
@ -598,7 +611,7 @@ public final class ReflectHelper {
public static void checkGetAndIsVariants( public static void checkGetAndIsVariants(
Class containerClass, Class<?> containerClass,
String propertyName, String propertyName,
Method getMethod, Method getMethod,
Method isMethod) { Method isMethod) {
@ -608,7 +621,7 @@ public final class ReflectHelper {
throw new MappingException( throw new MappingException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Class '%s' declares both 'get' [%s] and 'is' [%s] variants of getter for property '%s'", "Class<?> '%s' declares both 'get' [%s] and 'is' [%s] variants of getter for property '%s'",
containerClass.getName(), containerClass.getName(),
getMethod, getMethod,
isMethod, isMethod,
@ -619,11 +632,11 @@ public final class ReflectHelper {
} }
public static void verifyNoGetVariantExists( public static void verifyNoGetVariantExists(
Class containerClass, Class<?> containerClass,
String propertyName, String propertyName,
Method isMethod, Method isMethod,
String stemName) { String stemName) {
// verify that the Class does not also define a method with the same stem name with 'is' // verify that the Class<?> does not also define a method with the same stem name with 'is'
try { try {
final Method getMethod = containerClass.getDeclaredMethod( "get" + stemName ); final Method getMethod = containerClass.getDeclaredMethod( "get" + stemName );
// No such method should throw the caught exception. So if we get here, there was // No such method should throw the caught exception. So if we get here, there was
@ -636,7 +649,7 @@ public final class ReflectHelper {
} }
} }
public static Method getterMethodOrNull(Class containerJavaType, String propertyName) { public static Method getterMethodOrNull(Class<?> containerJavaType, String propertyName) {
try { try {
return findGetterMethod( containerJavaType, propertyName ); return findGetterMethod( containerJavaType, propertyName );
} }
@ -645,8 +658,8 @@ public final class ReflectHelper {
} }
} }
public static Method setterMethodOrNull(final Class containerClass, final String propertyName, final Class propertyType) { public static Method setterMethodOrNull(final Class<?> containerClass, final String propertyName, final Class<?> propertyType) {
Class checkClass = containerClass; Class<?> checkClass = containerClass;
Method setter = null; Method setter = null;
// check containerClass, and then its super types (if any) // check containerClass, and then its super types (if any)
@ -670,8 +683,8 @@ public final class ReflectHelper {
return setter; // might be null return setter; // might be null
} }
public static Method setterMethodOrNullBySetterName(final Class containerClass, final String setterName, final Class propertyType) { public static Method setterMethodOrNullBySetterName(final Class<?> containerClass, final String setterName, final Class<?> propertyType) {
Class checkClass = containerClass; Class<?> checkClass = containerClass;
Method setter = null; Method setter = null;
// check containerClass, and then its super types (if any) // check containerClass, and then its super types (if any)
@ -695,10 +708,10 @@ public final class ReflectHelper {
return setter; // might be null return setter; // might be null
} }
private static Method setterOrNullBySetterName(Class[] interfaces, String setterName, Class propertyType) { private static Method setterOrNullBySetterName(Class<?>[] interfaces, String setterName, Class<?> propertyType) {
Method setter = null; Method setter = null;
for ( int i = 0; setter == null && i < interfaces.length; ++i ) { for ( int i = 0; setter == null && i < interfaces.length; ++i ) {
final Class anInterface = interfaces[i]; final Class<?> anInterface = interfaces[i];
setter = setterOrNullBySetterName( anInterface, setterName, propertyType ); setter = setterOrNullBySetterName( anInterface, setterName, propertyType );
if ( setter == null ) { if ( setter == null ) {
// if no setter found yet, check all implemented interfaces of interface // if no setter found yet, check all implemented interfaces of interface
@ -708,7 +721,7 @@ public final class ReflectHelper {
return setter; return setter;
} }
private static Method setterOrNullBySetterName(Class theClass, String setterName, Class propertyType) { private static Method setterOrNullBySetterName(Class<?> theClass, String setterName, Class<?> propertyType) {
Method potentialSetter = null; Method potentialSetter = null;
for ( Method method : theClass.getDeclaredMethods() ) { for ( Method method : theClass.getDeclaredMethods() ) {
@ -724,7 +737,7 @@ public final class ReflectHelper {
return potentialSetter; return potentialSetter;
} }
public static Method findSetterMethod(final Class containerClass, final String propertyName, final Class propertyType) { public static Method findSetterMethod(final Class<?> containerClass, final String propertyName, final Class<?> propertyType) {
final Method setter = setterMethodOrNull( containerClass, propertyName, propertyType ); final Method setter = setterMethodOrNull( containerClass, propertyName, propertyType );
if ( setter == null ) { if ( setter == null ) {
throw new PropertyNotFoundException( throw new PropertyNotFoundException(
@ -739,10 +752,10 @@ public final class ReflectHelper {
return setter; return setter;
} }
private static Method setterOrNull(Class[] interfaces, String propertyName, Class propertyType) { private static Method setterOrNull(Class<?>[] interfaces, String propertyName, Class<?> propertyType) {
Method setter = null; Method setter = null;
for ( int i = 0; setter == null && i < interfaces.length; ++i ) { for ( int i = 0; setter == null && i < interfaces.length; ++i ) {
final Class anInterface = interfaces[i]; final Class<?> anInterface = interfaces[i];
setter = setterOrNull( anInterface, propertyName, propertyType ); setter = setterOrNull( anInterface, propertyName, propertyType );
if ( setter == null ) { if ( setter == null ) {
// if no setter found yet, check all implemented interfaces of interface // if no setter found yet, check all implemented interfaces of interface
@ -752,7 +765,7 @@ public final class ReflectHelper {
return setter; return setter;
} }
private static Method setterOrNull(Class theClass, String propertyName, Class propertyType) { private static Method setterOrNull(Class<?> theClass, String propertyName, Class<?> propertyType) {
Method potentialSetter = null; Method potentialSetter = null;
for ( Method method : theClass.getDeclaredMethods() ) { for ( Method method : theClass.getDeclaredMethods() ) {
@ -775,7 +788,7 @@ public final class ReflectHelper {
/** /**
* Similar to {@link #getterMethodOrNull}, except that here we are just looking for the * Similar to {@link #getterMethodOrNull}, except that here we are just looking for the
* corresponding getter for a field (defined as field access) if one exists. * corresponding getter for a field (defined as field access) if one exists.
* * <p>
* We do not look at supers, although conceivably the super could declare the method * We do not look at supers, although conceivably the super could declare the method
* as an abstract - but again, that is such an edge case... * as an abstract - but again, that is such an edge case...
*/ */
@ -876,7 +889,7 @@ public final class ReflectHelper {
return (Class<T>) ( (ParameterizedType) type ).getRawType(); return (Class<T>) ( (ParameterizedType) type ).getRawType();
} }
else if ( type instanceof TypeVariable ) { else if ( type instanceof TypeVariable ) {
return getClass( ( (TypeVariable) type ).getBounds()[0] ); return getClass( ( (TypeVariable<?>) type ).getBounds()[0] );
} }
else if ( type instanceof WildcardType ) { else if ( type instanceof WildcardType ) {
return getClass( ( (WildcardType) type ).getUpperBounds()[0] ); return getClass( ( (WildcardType) type ).getUpperBounds()[0] );

View File

@ -25,7 +25,7 @@ public class EmbeddableInstantiatorRecordStandard extends AbstractPojoInstantiat
super( javaType ); super( javaType );
final Class<?>[] componentTypes = ReflectHelper.getRecordComponentTypes( javaType ); final Class<?>[] componentTypes = ReflectHelper.getRecordComponentTypes( javaType );
this.constructor = ReflectHelper.getConstructor( javaType, componentTypes ); this.constructor = ReflectHelper.getConstructorOrNull( javaType, componentTypes );
} }
@Override @Override

View File

@ -24,7 +24,6 @@ import java.time.ZonedDateTime;
import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAccessor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -88,7 +87,6 @@ import org.hibernate.query.sqm.ParsingException;
import org.hibernate.query.sqm.SetOperator; import org.hibernate.query.sqm.SetOperator;
import org.hibernate.query.sqm.SqmExpressible; import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.SqmTreeCreationLogger; import org.hibernate.query.sqm.SqmTreeCreationLogger;
import org.hibernate.query.sqm.StrictJpaComplianceViolation; import org.hibernate.query.sqm.StrictJpaComplianceViolation;
import org.hibernate.query.sqm.TemporalUnit; import org.hibernate.query.sqm.TemporalUnit;
@ -108,7 +106,6 @@ import org.hibernate.query.sqm.produce.function.FunctionArgumentException;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.spi.ParameterDeclarationContext; import org.hibernate.query.sqm.spi.ParameterDeclarationContext;
import org.hibernate.query.sqm.spi.SqmCreationContext; import org.hibernate.query.sqm.spi.SqmCreationContext;
import org.hibernate.query.sqm.tree.AbstractSqmDmlStatement;
import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.SqmQuery; import org.hibernate.query.sqm.tree.SqmQuery;
import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.SqmStatement;
@ -214,9 +211,7 @@ import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.query.sqm.tree.select.SqmSortSpecification; import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
import org.hibernate.query.sqm.tree.select.SqmSubQuery; import org.hibernate.query.sqm.tree.select.SqmSubQuery;
import org.hibernate.query.sqm.tree.update.SqmAssignment; import org.hibernate.query.sqm.tree.update.SqmAssignment;
import org.hibernate.query.sqm.tree.update.SqmSetClause;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.tree.cte.CteMaterialization; import org.hibernate.sql.ast.tree.cte.CteMaterialization;
import org.hibernate.sql.ast.tree.cte.CteSearchClauseKind; import org.hibernate.sql.ast.tree.cte.CteSearchClauseKind;
@ -316,14 +311,17 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
HqlParser.StatementContext hqlParseTree, HqlParser.StatementContext hqlParseTree,
Class<R> expectedResultType, Class<R> expectedResultType,
SqmCreationOptions creationOptions, SqmCreationOptions creationOptions,
SqmCreationContext creationContext) { SqmCreationContext creationContext,
return new SemanticQueryBuilder<>( expectedResultType, creationOptions, creationContext ).visitStatement( hqlParseTree ); String query) {
return new SemanticQueryBuilder<>( expectedResultType, creationOptions, creationContext, query )
.visitStatement( hqlParseTree );
} }
private final Class<R> expectedResultType; private final Class<R> expectedResultType;
private final String expectedResultEntity; private final String expectedResultEntity;
private final SqmCreationOptions creationOptions; private final SqmCreationOptions creationOptions;
private final SqmCreationContext creationContext; private final SqmCreationContext creationContext;
private final String query;
private final Stack<DotIdentifierConsumer> dotIdentifierConsumerStack; private final Stack<DotIdentifierConsumer> dotIdentifierConsumerStack;
@ -347,26 +345,30 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
public SemanticQueryBuilder( public SemanticQueryBuilder(
Class<R> expectedResultType, Class<R> expectedResultType,
SqmCreationOptions creationOptions, SqmCreationOptions creationOptions,
SqmCreationContext creationContext) { SqmCreationContext creationContext,
this( expectedResultType, null, creationOptions, creationContext ); String query) {
this( expectedResultType, null, creationOptions, creationContext, query );
} }
public SemanticQueryBuilder( public SemanticQueryBuilder(
String expectedResultEntity, String expectedResultEntity,
SqmCreationOptions creationOptions, SqmCreationOptions creationOptions,
SqmCreationContext creationContext) { SqmCreationContext creationContext,
this( null, expectedResultEntity, creationOptions, creationContext ); String query) {
this( null, expectedResultEntity, creationOptions, creationContext, query );
} }
private SemanticQueryBuilder( private SemanticQueryBuilder(
Class<R> expectedResultType, Class<R> expectedResultType,
String expectedResultEntity, String expectedResultEntity,
SqmCreationOptions creationOptions, SqmCreationOptions creationOptions,
SqmCreationContext creationContext) { SqmCreationContext creationContext,
String query) {
this.expectedResultType = expectedResultType; this.expectedResultType = expectedResultType;
this.expectedResultEntity = expectedResultEntity; this.expectedResultEntity = expectedResultEntity;
this.creationOptions = creationOptions; this.creationOptions = creationOptions;
this.creationContext = creationContext; this.creationContext = creationContext;
this.query = query;
this.dotIdentifierConsumerStack = new StandardStack<>( this.dotIdentifierConsumerStack = new StandardStack<>(
DotIdentifierConsumer.class, DotIdentifierConsumer.class,
new BasicDotIdentifierConsumer( this ) new BasicDotIdentifierConsumer( this )
@ -476,10 +478,9 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final SqmRoot<R> root = visitTargetEntity( dmlTargetContext ); final SqmRoot<R> root = visitTargetEntity( dmlTargetContext );
if ( root.getModel() instanceof SqmPolymorphicRootDescriptor<?> ) { if ( root.getModel() instanceof SqmPolymorphicRootDescriptor<?> ) {
throw new SemanticException( throw new SemanticException(
String.format( "Target type '" + root.getModel().getHibernateEntityName()
"Target type '%s' in 'insert' statement is not an entity", + "' in 'insert' statement is not an entity",
root.getModel().getHibernateEntityName() query
)
); );
} }
@ -587,6 +588,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
return null; return null;
} }
final SqmCreationProcessingState processingState = processingStateStack.getCurrent(); final SqmCreationProcessingState processingState = processingStateStack.getCurrent();
@SuppressWarnings("unchecked")
final SqmInsertStatement<R> statement = (SqmInsertStatement<R>) processingState.getProcessingQuery(); final SqmInsertStatement<R> statement = (SqmInsertStatement<R>) processingState.getProcessingQuery();
final SqmConflictClause<R> conflictClause = new SqmConflictClause<>( statement ); final SqmConflictClause<R> conflictClause = new SqmConflictClause<>( statement );
final HqlParser.ConflictTargetContext conflictTargetContext = ctx.conflictTarget(); final HqlParser.ConflictTargetContext conflictTargetContext = ctx.conflictTarget();
@ -869,7 +871,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
"Cycle attribute '%s' not found in the CTE %s", "Cycle attribute '%s' not found in the CTE %s",
attributeName, attributeName,
cteDefinition.getName() cteDefinition.getName()
) ),
query
); );
} }
cycleAttributes.add( attribute ); cycleAttributes.add( attribute );
@ -929,7 +932,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
"Search attribute '%s' not found in the CTE %s", "Search attribute '%s' not found in the CTE %s",
attributeName, attributeName,
cteDefinition.getName() cteDefinition.getName()
) ),
query
); );
} }
SortDirection sortOrder = SortDirection.ASCENDING; SortDirection sortOrder = SortDirection.ASCENDING;
@ -946,7 +950,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
sortOrder = SortDirection.DESCENDING; sortOrder = SortDirection.DESCENDING;
break; break;
default: default:
throw new SemanticException( "Unrecognized sort ordering: " + sortCtx.getText() ); throw new UnsupportedOperationException( "Unrecognized sort ordering: " + sortCtx.getText() );
} }
index++; index++;
} }
@ -960,7 +964,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
nullPrecedence = NullPrecedence.LAST; nullPrecedence = NullPrecedence.LAST;
break; break;
default: default:
throw new SemanticException( "Unrecognized null precedence: " + nullsPrecedenceContext.getText() ); throw new UnsupportedOperationException( "Unrecognized null precedence: " + nullsPrecedenceContext.getText() );
} }
} }
} }
@ -1169,7 +1173,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( processingStateStack.depth() > 1 && orderByClause == null ) { if ( processingStateStack.depth() > 1 && orderByClause == null ) {
throw new SemanticException( throw new SemanticException(
"A 'limit', 'offset', or 'fetch' clause requires an 'order by' clause when used in a subquery" "A 'limit', 'offset', or 'fetch' clause requires an 'order by' clause when used in a subquery",
query
); );
} }
@ -1191,7 +1196,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
sqmQueryPart.setFetchExpression( (SqmExpression<? extends Number>) visitLimitClause(limitClauseContext) ); sqmQueryPart.setFetchExpression( (SqmExpression<? extends Number>) visitLimitClause(limitClauseContext) );
} }
else { else {
throw new SemanticException("The 'limit' and 'fetch' clauses may not be used together" ); throw new SemanticException("The 'limit' and 'fetch' clauses may not be used together", query );
} }
} }
@ -1258,16 +1263,16 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( expectedResultEntity != null ) { if ( expectedResultEntity != null ) {
final EntityDomainType<R> entityDescriptor = jpaMetamodel.entity( expectedResultEntity ); final EntityDomainType<R> entityDescriptor = jpaMetamodel.entity( expectedResultEntity );
if ( entityDescriptor == null ) { if ( entityDescriptor == null ) {
throw new SemanticException("Query has no 'from' clause, and the result type '" throw new SemanticException( "Query has no 'from' clause, and the result type '"
+ expectedResultEntity + "' is not an entity type"); + expectedResultEntity + "' is not an entity type", query );
} }
return entityDescriptor; return entityDescriptor;
} }
else if ( expectedResultType != null ) { else if ( expectedResultType != null ) {
final EntityDomainType<R> entityDescriptor = jpaMetamodel.findEntityType( expectedResultType ); final EntityDomainType<R> entityDescriptor = jpaMetamodel.findEntityType( expectedResultType );
if ( entityDescriptor == null ) { if ( entityDescriptor == null ) {
throw new SemanticException("Query has no 'from' clause, and the result type '" throw new SemanticException( "Query has no 'from' clause, and the result type '"
+ expectedResultType.getSimpleName() + "' is not an entity type"); + expectedResultType.getSimpleName() + "' is not an entity type", query );
} }
return entityDescriptor; return entityDescriptor;
} }
@ -1286,7 +1291,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( fromClause.getNumberOfRoots() == 0 ) { if ( fromClause.getNumberOfRoots() == 0 ) {
throw new SemanticException( "query has no 'select' clause, and no root entities" throw new SemanticException( "query has no 'select' clause, and no root entities"
+ " (every selection query must have an explicit 'select', an explicit 'from', or an explicit entity result type)"); + " (every selection query must have an explicit 'select', an explicit 'from', or an explicit entity result type)",
query );
} }
final NodeBuilder nodeBuilder = creationContext.getNodeBuilder(); final NodeBuilder nodeBuilder = creationContext.getNodeBuilder();
@ -1309,13 +1315,15 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( fromClause.getNumberOfRoots() > 1 ) { if ( fromClause.getNumberOfRoots() > 1 ) {
// multiple root entities // multiple root entities
throw new SemanticException( "Query has no 'select' clause, and multiple root entities, but query result type is an entity class" throw new SemanticException( "Query has no 'select' clause, and multiple root entities, but query result type is an entity class"
+ " (specify an explicit 'select' list, or a different result type, for example, 'Object[].class')"); + " (specify an explicit 'select' list, or a different result type, for example, 'Object[].class')",
query );
} }
else { else {
final SqmRoot<?> sqmRoot = fromClause.getRoots().get(0); final SqmRoot<?> sqmRoot = fromClause.getRoots().get(0);
if ( sqmRoot instanceof SqmCteRoot ) { if ( sqmRoot instanceof SqmCteRoot ) {
throw new SemanticException( "Query has no 'select' clause, and the 'from' clause refers to a CTE, but query result type is an entity class" throw new SemanticException( "Query has no 'select' clause, and the 'from' clause refers to a CTE, but query result type is an entity class"
+ " (specify an explicit 'select' list)"); + " (specify an explicit 'select' list)",
query );
} }
else { else {
// exactly one root entity, return it // exactly one root entity, return it
@ -1429,7 +1437,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
); );
} }
catch (ClassLoadingException e) { catch (ClassLoadingException e) {
throw new SemanticException( "Could not resolve class '" + className + "' named for instantiation" ); throw new SemanticException( "Could not resolve class '" + className + "' named for instantiation",
query );
} }
} }
else { else {
@ -1456,6 +1465,12 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
dynamicInstantiation.addArgument( visitInstantiationArgument( arg ) ); dynamicInstantiation.addArgument( visitInstantiationArgument( arg ) );
} }
if ( !dynamicInstantiation.checkInstantiation( creationContext.getTypeConfiguration() ) ) {
throw new SemanticException( "No matching constructor for type '"
+ dynamicInstantiation.getJavaType().getSimpleName() + "'",
query );
}
return dynamicInstantiation; return dynamicInstantiation;
} }
@ -1468,20 +1483,16 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
} }
private Class<?> classForName(String className) { private Class<?> classForName(String className) {
return creationContext.getServiceRegistry().getService( ClassLoaderService.class ).classForName( className ); return creationContext.getServiceRegistry().requireService( ClassLoaderService.class ).classForName( className );
} }
@Override @Override
public SqmDynamicInstantiationArgument<?> visitInstantiationArgument(HqlParser.InstantiationArgumentContext ctx) { public SqmDynamicInstantiationArgument<?> visitInstantiationArgument(HqlParser.InstantiationArgumentContext ctx) {
final String alias; final HqlParser.VariableContext variable = ctx.variable();
if ( ctx.getChildCount() > 1 ) { final String alias = variable == null ? null : extractAlias( variable );
alias = extractAlias( (HqlParser.VariableContext) ctx.getChild( ctx.getChildCount() - 1 ) );
}
else {
alias = null;
}
final SqmSelectableNode<?> argExpression = (SqmSelectableNode<?>) ctx.getChild( 0 ).accept( this ); final SqmSelectableNode<?> argExpression =
(SqmSelectableNode<?>) ctx.instantiationArgumentExpression().accept( this );
final SqmDynamicInstantiationArgument<?> argument = new SqmDynamicInstantiationArgument<>( final SqmDynamicInstantiationArgument<?> argument = new SqmDynamicInstantiationArgument<>(
argExpression, argExpression,
@ -1504,7 +1515,9 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
true true
); );
if ( sqmFromByAlias == null ) { if ( sqmFromByAlias == null ) {
throw new SemanticException( "Could not resolve alias '" + alias + "' in selection [" + ctx.getText() + "]" ); throw new SemanticException( "Could not resolve alias '" + alias
+ "' in selection [" + ctx.getText() + "]",
query );
} }
return sqmFromByAlias; return sqmFromByAlias;
} }
@ -1563,7 +1576,9 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
nodeByPosition = processingState.getPathRegistry().findAliasedNodeByPosition( position ); nodeByPosition = processingState.getPathRegistry().findAliasedNodeByPosition( position );
} }
if ( nodeByPosition == null ) { if ( nodeByPosition == null ) {
throw new SemanticException( "Numeric literal '" + position + "' used in 'group by' does not match a registered select item" ); throw new SemanticException( "Numeric literal '" + position
+ "' used in 'group by' does not match a registered select item",
query );
} }
return new SqmAliasedNodeRef( position, integerDomainType, nodeBuilder); return new SqmAliasedNodeRef( position, integerDomainType, nodeBuilder);
@ -1701,7 +1716,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
allowPositionalOrAliases allowPositionalOrAliases
); );
if ( sortExpression == null ) { if ( sortExpression == null ) {
throw new SemanticException( "Could not resolve sort expression: '" + ctx.sortExpression().getText() + "'" ); throw new SemanticException( "Could not resolve sort expression: '" + ctx.sortExpression().getText() + "'",
query );
} }
if ( sortExpression instanceof SqmLiteral || sortExpression instanceof SqmParameter ) { if ( sortExpression instanceof SqmLiteral || sortExpression instanceof SqmParameter ) {
HqlLogging.QUERY_LOGGER.debugf( "Questionable sorting by constant value : %s", sortExpression ); HqlLogging.QUERY_LOGGER.debugf( "Questionable sorting by constant value : %s", sortExpression );
@ -2014,7 +2030,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( processingStateStack.depth() > 1 ) { if ( processingStateStack.depth() > 1 ) {
throw new SemanticException( throw new SemanticException(
"Implicitly-polymorphic domain path in subquery '" + entityDescriptor.getName() +"'" "Implicitly-polymorphic domain path in subquery '" + entityDescriptor.getName() + "'",
query
); );
} }
} }
@ -2060,7 +2077,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
); );
return ((SqmCorrelation<?, ?>) correlation).getCorrelatedRoot(); return ((SqmCorrelation<?, ?>) correlation).getCorrelatedRoot();
} }
throw new SemanticException( "Could not resolve entity or correlation path '" + name + "'" ); throw new SemanticException( "Could not resolve entity or correlation path '" + name + "'", query );
} }
final SqmCteStatement<?> cteStatement = findCteStatement( name ); final SqmCteStatement<?> cteStatement = findCteStatement( name );
if ( cteStatement != null ) { if ( cteStatement != null ) {
@ -2131,7 +2148,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
.resolveHqlEntityReference( name ); .resolveHqlEntityReference( name );
if ( entityDescriptor instanceof SqmPolymorphicRootDescriptor ) { if ( entityDescriptor instanceof SqmPolymorphicRootDescriptor ) {
throw new SemanticException( "Unmapped polymorphic reference cannot be used as a target of 'cross join'" ); throw new SemanticException( "Unmapped polymorphic reference cannot be used as a target of 'cross join'",
query );
} }
final SqmCrossJoin<T> join = new SqmCrossJoin<>( final SqmCrossJoin<T> join = new SqmCrossJoin<>(
entityDescriptor, entityDescriptor,
@ -2157,7 +2175,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final boolean fetch = parserJoin.FETCH() != null; final boolean fetch = parserJoin.FETCH() != null;
if ( fetch && processingStateStack.depth() > 1 ) { if ( fetch && processingStateStack.depth() > 1 ) {
throw new SemanticException( "The 'from' clause of a subquery has a 'fetch'" ); throw new SemanticException( "The 'from' clause of a subquery has a 'fetch'", query );
} }
dotIdentifierConsumerStack.push( new QualifiedJoinPathConsumer( sqmRoot, joinType, fetch, alias, this ) ); dotIdentifierConsumerStack.push( new QualifiedJoinPathConsumer( sqmRoot, joinType, fetch, alias, this ) );
@ -2178,7 +2196,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
} }
} }
if ( joinRestrictionContext != null && attributeJoin.isFetched() ) { if ( joinRestrictionContext != null && attributeJoin.isFetched() ) {
throw new SemanticException( "Fetch join has a 'with' clause (use a filter instead)" ); throw new SemanticException( "Fetch join has a 'with' clause (use a filter instead)", query );
} }
} }
@ -2222,7 +2240,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
} }
else if ( joinTargetContext instanceof HqlParser.JoinSubqueryContext ) { else if ( joinTargetContext instanceof HqlParser.JoinSubqueryContext ) {
if ( fetch ) { if ( fetch ) {
throw new SemanticException( "The 'from' clause of a subquery has a 'fetch' join" ); throw new SemanticException( "The 'from' clause of a subquery has a 'fetch' join", query );
} }
if ( getCreationOptions().useStrictJpaCompliance() ) { if ( getCreationOptions().useStrictJpaCompliance() ) {
throw new StrictJpaComplianceViolation( throw new StrictJpaComplianceViolation(
@ -2397,7 +2415,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
); );
} }
else { else {
throw new SemanticException( "Operand of 'is empty' operator must be a plural path" ); throw new SemanticException( "Operand of 'is empty' operator must be a plural path", query );
} }
} }
@ -2598,7 +2616,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final String escape = unquoteStringLiteral( terminalNode.getText() ); final String escape = unquoteStringLiteral( terminalNode.getText() );
if ( escape.length() != 1 ) { if ( escape.length() != 1 ) {
throw new SemanticException( throw new SemanticException(
"Escape character literals must have exactly a single character, but found: " + escape "Escape character literals must have exactly a single character, but found: " + escape,
query
); );
} }
return new SqmLiteral<>( return new SqmLiteral<>(
@ -2622,7 +2641,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
); );
} }
else { else {
throw new SemanticException( "Operand of 'member of' operator must be a plural path" ); throw new SemanticException( "Operand of 'member of' operator must be a plural path", query );
} }
} }
@ -2740,7 +2759,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
public SqmPredicate visitBooleanExpressionPredicate(HqlParser.BooleanExpressionPredicateContext ctx) { public SqmPredicate visitBooleanExpressionPredicate(HqlParser.BooleanExpressionPredicateContext ctx) {
final SqmExpression<?> expression = (SqmExpression<?>) ctx.expression().accept( this ); final SqmExpression<?> expression = (SqmExpression<?>) ctx.expression().accept( this );
if ( expression.getJavaType() != Boolean.class ) { if ( expression.getJavaType() != Boolean.class ) {
throw new SemanticException( "Non-boolean expression used in predicate context: " + ctx.getText() ); throw new SemanticException( "Non-boolean expression used in predicate context: " + ctx.getText(), query );
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final SqmExpression<Boolean> booleanExpression = (SqmExpression<Boolean>) expression; final SqmExpression<Boolean> booleanExpression = (SqmExpression<Boolean>) expression;
@ -3971,20 +3990,30 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
else { else {
final FunctionKind functionKind = functionTemplate.getFunctionKind(); final FunctionKind functionKind = functionTemplate.getFunctionKind();
if ( ctx.filterClause() != null && functionKind == FunctionKind.NORMAL ) { if ( ctx.filterClause() != null && functionKind == FunctionKind.NORMAL ) {
throw new SemanticException( "'FILTER' clause is illegal for non-aggregate function: " + functionName ); throw new SemanticException( "'FILTER' clause is illegal for non-aggregate function: "
+ functionName,
query );
} }
if ( ctx.overClause() != null && functionKind == FunctionKind.NORMAL ) { if ( ctx.overClause() != null && functionKind == FunctionKind.NORMAL ) {
throw new SemanticException( "'OVER' clause is illegal for non-aggregate function: " + functionName); throw new SemanticException( "'OVER' clause is illegal for non-aggregate function: "
+ functionName,
query );
} }
if ( ctx.withinGroupClause() != null && functionKind == FunctionKind.NORMAL ) { if ( ctx.withinGroupClause() != null && functionKind == FunctionKind.NORMAL ) {
throw new SemanticException( "'WITHIN' GROUP clause is illegal for non-aggregate function: " + functionName); throw new SemanticException( "'WITHIN' GROUP clause is illegal for non-aggregate function: "
+ functionName,
query );
} }
if ( ctx.overClause() == null && functionKind == FunctionKind.WINDOW ) { if ( ctx.overClause() == null && functionKind == FunctionKind.WINDOW ) {
throw new SemanticException( "'OVER' clause is mandatory for window-only function: " + functionName ); throw new SemanticException( "'OVER' clause is mandatory for window-only function: "
+ functionName,
query );
} }
if ( ctx.withinGroupClause() == null && ctx.overClause() == null if ( ctx.withinGroupClause() == null && ctx.overClause() == null
&& functionKind == FunctionKind.ORDERED_SET_AGGREGATE ) { && functionKind == FunctionKind.ORDERED_SET_AGGREGATE ) {
throw new SemanticException( "'WITHIN GROUP' or 'OVER' clause is mandatory for ordered set aggregate function: " + functionName ); throw new SemanticException( "'WITHIN GROUP' or 'OVER' clause is mandatory for ordered set aggregate function: "
+ functionName,
query );
} }
if ( ctx.nullsClause() != null ) { if ( ctx.nullsClause() != null ) {
@ -3996,11 +4025,15 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
case "nth_value": case "nth_value":
break; break;
default: default:
throw new SemanticException( "'RESPECT NULLS' or 'IGNORE NULLS' are illegal for function: " + functionName ); throw new SemanticException( "'RESPECT NULLS' or 'IGNORE NULLS' are illegal for function: "
+ functionName,
query );
} }
} }
if ( ctx.nthSideClause() != null && !"nth_value".equals( functionName ) ) { if ( ctx.nthSideClause() != null && !"nth_value".equals( functionName ) ) {
throw new SemanticException( "'FROM FIRST' or 'FROM LAST' are illegal for function: " + functionName ); throw new SemanticException( "'FROM FIRST' or 'FROM LAST' are illegal for function: "
+ functionName,
query );
} }
return functionTemplate; return functionTemplate;
} }
@ -4049,7 +4082,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final SqmFunctionDescriptor functionTemplate = getFunctionDescriptor( "listagg" ); final SqmFunctionDescriptor functionTemplate = getFunctionDescriptor( "listagg" );
if ( functionTemplate == null ) { if ( functionTemplate == null ) {
throw new SemanticException( "The listagg() function was not registered for the dialect" ); throw new SemanticException( "The listagg() function was not registered for the dialect", query );
} }
return applyOverClause( return applyOverClause(
@ -4510,8 +4543,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( !(referencedPathSource instanceof PluralPersistentAttribute ) ) { if ( !(referencedPathSource instanceof PluralPersistentAttribute ) ) {
//TODO: improve this message //TODO: improve this message
throw new SemanticException( "Path is not a plural path '" throw new SemanticException( "Path is not a plural path '" + pluralAttributePath.getNavigablePath() + "'",
+ pluralAttributePath.getNavigablePath() + "'" ); query );
} }
final SqmSubQuery<?> subQuery = new SqmSubQuery<>( final SqmSubQuery<?> subQuery = new SqmSubQuery<>(
processingStateStack.getCurrent().getProcessingQuery(), processingStateStack.getCurrent().getProcessingQuery(),
@ -4768,7 +4801,9 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final String padCharText = ctx.STRING_LITERAL().getText(); final String padCharText = ctx.STRING_LITERAL().getText();
if ( padCharText.length() != 3 ) { if ( padCharText.length() != 3 ) {
throw new SemanticException( "Pad character for pad() function must be single character, found '" + padCharText + "'" ); throw new SemanticException( "Pad character for pad() function must be single character, found '"
+ padCharText + "'",
query );
} }
return new SqmLiteral<>( return new SqmLiteral<>(
@ -4831,7 +4866,9 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
else { else {
trimCharText = unquoteStringLiteral( ctx.getText() ); trimCharText = unquoteStringLiteral( ctx.getText() );
if ( trimCharText.length() != 1 ) { if ( trimCharText.length() != 1 ) {
throw new SemanticException( "Trim character for trim() function must be single character, found '" + trimCharText + "'" ); throw new SemanticException( "Trim character for trim() function must be single character, found '"
+ trimCharText + "'",
query );
} }
} }
} }
@ -5145,7 +5182,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final String treatTargetEntityName = final String treatTargetEntityName =
getCreationContext().getJpaMetamodel().qualifyImportableName( treatTargetName ); getCreationContext().getJpaMetamodel().qualifyImportableName( treatTargetName );
if ( treatTargetEntityName == null ) { if ( treatTargetEntityName == null ) {
throw new SemanticException( "Could not resolve treat target type '" + treatTargetName + "'" ); throw new SemanticException( "Could not resolve treat target type '" + treatTargetName + "'", query );
} }
final boolean hasContinuation = ctx.getChildCount() == 7; final boolean hasContinuation = ctx.getChildCount() == 7;

View File

@ -72,7 +72,8 @@ public class StandardHqlTranslator implements HqlTranslator {
hqlParseTree, hqlParseTree,
expectedResultType, expectedResultType,
sqmCreationOptions, sqmCreationOptions,
sqmCreationContext sqmCreationContext,
query
); );
// Log the SQM tree (if enabled) // Log the SQM tree (if enabled)

View File

@ -9,8 +9,6 @@ package org.hibernate.query.sqm.tree.expression;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.type.descriptor.java.JavaType;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -18,8 +16,8 @@ public class Compatibility {
private Compatibility() { private Compatibility() {
} }
private static final Map<Class,Class> primitiveToWrapper; private static final Map<Class<?>,Class<?>> primitiveToWrapper;
private static final Map<Class,Class> wrapperToPrimitive; private static final Map<Class<?>,Class<?>> wrapperToPrimitive;
static { static {
primitiveToWrapper = new ConcurrentHashMap<>(); primitiveToWrapper = new ConcurrentHashMap<>();
wrapperToPrimitive = new ConcurrentHashMap<>(); wrapperToPrimitive = new ConcurrentHashMap<>();
@ -33,27 +31,26 @@ public class Compatibility {
map( double.class, Double.class ); map( double.class, Double.class );
} }
private static void map(Class primitive, Class wrapper) { private static void map(Class<?> primitive, Class<?> wrapper) {
primitiveToWrapper.put( primitive, wrapper ); primitiveToWrapper.put( primitive, wrapper );
wrapperToPrimitive.put( wrapper, primitive ); wrapperToPrimitive.put( wrapper, primitive );
} }
public static boolean isWrapper(Class potentialWrapper) { public static boolean isWrapper(Class<?> potentialWrapper) {
return wrapperToPrimitive.containsKey( potentialWrapper ); return wrapperToPrimitive.containsKey( potentialWrapper );
} }
public static Class primitiveEquivalent(Class potentialWrapper) { public static Class<?> primitiveEquivalent(Class<?> potentialWrapper) {
assert isWrapper( potentialWrapper ); assert isWrapper( potentialWrapper );
return wrapperToPrimitive.get( potentialWrapper ); return wrapperToPrimitive.get( potentialWrapper );
} }
public static Class wrapperEquivalent(Class primitive) { public static Class<?> wrapperEquivalent(Class<?> primitive) {
assert primitive.isPrimitive(); assert primitive.isPrimitive();
return primitiveToWrapper.get( primitive ); return primitiveToWrapper.get( primitive );
} }
@SuppressWarnings("unchecked") public static boolean areAssignmentCompatible(Class<?> to, Class<?> from) {
public static boolean areAssignmentCompatible(Class to, Class from) {
assert to != null; assert to != null;
assert from != null; assert from != null;
@ -79,7 +76,7 @@ public class Compatibility {
return false; return false;
} }
private static boolean areAssignmentCompatiblePrimitive(Class to, Class from) { private static boolean areAssignmentCompatiblePrimitive(Class<?> to, Class<?> from) {
assert to != null; assert to != null;
assert from != null; assert from != null;
@ -99,38 +96,38 @@ public class Compatibility {
} }
else if ( isIntegralTypePrimitive( to ) ) { else if ( isIntegralTypePrimitive( to ) ) {
return from == byte.class return from == byte.class
|| isCompatibleIntegralTypePrimitive( to, from ) || isCompatibleIntegralTypePrimitive( to, from )
// this would for sure cause loss of precision // this would for sure cause loss of precision
|| isFloatingTypePrimitive( from ); || isFloatingTypePrimitive( from );
} }
else if ( isFloatingTypePrimitive( to ) ) { else if ( isFloatingTypePrimitive( to ) ) {
return from == byte.class return from == byte.class
|| isIntegralTypePrimitive( from ) || isIntegralTypePrimitive( from )
|| isCompatibleFloatingTypePrimitive( to, from ); || isCompatibleFloatingTypePrimitive( to, from );
} }
return false; return false;
} }
public static boolean isIntegralType(Class potentialIntegral) { public static boolean isIntegralType(Class<?> potentialIntegral) {
if ( potentialIntegral.isPrimitive() ) { if ( potentialIntegral.isPrimitive() ) {
return isIntegralTypePrimitive( potentialIntegral ); return isIntegralTypePrimitive( potentialIntegral );
} }
return isWrapper( potentialIntegral ) return isWrapper( potentialIntegral )
&& isIntegralTypePrimitive( primitiveEquivalent( potentialIntegral ) ); && isIntegralTypePrimitive( primitiveEquivalent( potentialIntegral ) );
} }
private static boolean isIntegralTypePrimitive(Class potentialIntegral) { private static boolean isIntegralTypePrimitive(Class<?> potentialIntegral) {
assert potentialIntegral.isPrimitive(); assert potentialIntegral.isPrimitive();
return potentialIntegral == short.class return potentialIntegral == short.class
|| potentialIntegral == int.class || potentialIntegral == int.class
|| potentialIntegral == long.class; || potentialIntegral == long.class;
} }
private static boolean isCompatibleIntegralTypePrimitive(Class to, Class from) { private static boolean isCompatibleIntegralTypePrimitive(Class<?> to, Class<?> from) {
assert isIntegralTypePrimitive( to ); assert isIntegralTypePrimitive( to );
assert from.isPrimitive(); assert from.isPrimitive();
@ -139,50 +136,34 @@ public class Compatibility {
} }
else if ( to == int.class ) { else if ( to == int.class ) {
return from == short.class return from == short.class
|| from == int.class; || from == int.class;
} }
else { else {
return isIntegralTypePrimitive( from ); return isIntegralTypePrimitive( from );
} }
} }
public static boolean isFloatingType(Class potentialFloating) { public static boolean isFloatingType(Class<?> potentialFloating) {
if ( potentialFloating.isPrimitive() ) { if ( potentialFloating.isPrimitive() ) {
return isFloatingTypePrimitive( potentialFloating ); return isFloatingTypePrimitive( potentialFloating );
} }
return isWrapper( potentialFloating ) return isWrapper( potentialFloating )
&& isFloatingTypePrimitive( primitiveEquivalent( potentialFloating ) ); && isFloatingTypePrimitive( primitiveEquivalent( potentialFloating ) );
} }
private static boolean isFloatingTypePrimitive(Class potentialFloating) { private static boolean isFloatingTypePrimitive(Class<?> potentialFloating) {
assert potentialFloating.isPrimitive(); assert potentialFloating.isPrimitive();
return potentialFloating == float.class return potentialFloating == float.class
|| potentialFloating == double.class; || potentialFloating == double.class;
} }
private static boolean isCompatibleFloatingTypePrimitive(Class to, Class from) { private static boolean isCompatibleFloatingTypePrimitive(Class<?> to, Class<?> from) {
assert isFloatingTypePrimitive( to ); assert isFloatingTypePrimitive( to );
assert from.isPrimitive(); assert from.isPrimitive();
if ( to == float.class ) { return to == float.class ? from == float.class : isFloatingTypePrimitive( from );
return from == float.class;
}
else {
return isFloatingTypePrimitive( from );
}
}
public static boolean areAssignmentCompatible(
JavaType to,
JavaType from) {
// todo (6.0) - base this in the descriptor.
// `JavaType#assignableFrom` ?
// Note from Christian: I think this is a good idea to allow honoring parameterized types
return areAssignmentCompatible( to.getJavaTypeClass(), from.getJavaTypeClass() );
} }
} }

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.query.sqm.tree.select; package org.hibernate.query.sqm.tree.select;
import java.lang.reflect.Constructor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -22,11 +23,14 @@ import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.jpa.AbstractJpaSelection; import org.hibernate.query.sqm.tree.jpa.AbstractJpaSelection;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import static java.util.stream.Collectors.toList;
import static org.hibernate.query.sqm.DynamicInstantiationNature.CLASS; import static org.hibernate.query.sqm.DynamicInstantiationNature.CLASS;
import static org.hibernate.query.sqm.DynamicInstantiationNature.LIST; import static org.hibernate.query.sqm.DynamicInstantiationNature.LIST;
import static org.hibernate.query.sqm.DynamicInstantiationNature.MAP; import static org.hibernate.query.sqm.DynamicInstantiationNature.MAP;
import static org.hibernate.sql.results.graph.instantiation.internal.InstantiationHelper.isConstructorCompatible;
/** /**
* Represents a dynamic instantiation ({@code select new XYZ(...) ...}) as part of the SQM. * Represents a dynamic instantiation ({@code select new XYZ(...) ...}) as part of the SQM.
@ -111,6 +115,30 @@ public class SqmDynamicInstantiation<T>
this.arguments = arguments; this.arguments = arguments;
} }
public boolean checkInstantiation(TypeConfiguration typeConfiguration) {
if ( getInstantiationTarget().getNature() == CLASS) {
if ( getArguments().stream().allMatch(arg -> arg.getAlias() != null ) ) {
// it's probably a bean injection-type instantiator, don't check it now
return true;
}
else {
final List<Class<?>> argTypes =
getArguments().stream()
.map(arg -> arg.getNodeJavaType().getJavaTypeClass())
.collect(toList());
for ( Constructor<?> constructor : getJavaType().getDeclaredConstructors() ) {
if ( isConstructorCompatible( constructor, argTypes, typeConfiguration ) ) {
return true;
}
}
return false;
}
}
else {
return true;
}
}
@Override @Override
public SqmDynamicInstantiation<T> copy(SqmCopyContext context) { public SqmDynamicInstantiation<T> copy(SqmCopyContext context) {
final SqmDynamicInstantiation<T> existing = context.getCopy( this ); final SqmDynamicInstantiation<T> existing = context.getCopy( this );

View File

@ -7,7 +7,6 @@
package org.hibernate.sql.results.graph.instantiation.internal; package org.hibernate.sql.results.graph.instantiation.internal;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.BitSet; import java.util.BitSet;
import java.util.HashSet; import java.util.HashSet;
@ -23,10 +22,11 @@ import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.instantiation.DynamicInstantiationResult; import org.hibernate.sql.results.graph.instantiation.DynamicInstantiationResult;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import static org.hibernate.query.sqm.tree.expression.Compatibility.areAssignmentCompatible; import static org.hibernate.sql.results.graph.instantiation.internal.InstantiationHelper.isConstructorCompatible;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -150,79 +150,59 @@ public class DynamicInstantiationResultImpl<R> implements DynamicInstantiationRe
new DynamicInstantiationAssemblerMapImpl( (JavaType<Map<?,?>>) javaType, argumentReaders ); new DynamicInstantiationAssemblerMapImpl( (JavaType<Map<?,?>>) javaType, argumentReaders );
} }
else { else {
// find a constructor matching argument types return assembler( areAllArgumentsAliased, duplicatedAliases, argumentReaders, creationState );
constructor_loop:
for ( Constructor<?> constructor : javaType.getJavaTypeClass().getDeclaredConstructors() ) {
final Type[] genericParameterTypes = constructor.getGenericParameterTypes();
if ( genericParameterTypes.length == argumentReaders.size() ) {
for ( int i = 0; i < argumentReaders.size(); i++ ) {
final Type parameterType = genericParameterTypes[i];
final ArgumentReader<?> argumentReader = argumentReaders.get( i );
final boolean assignmentCompatible;
if ( parameterType instanceof Class<?> ) {
assignmentCompatible = areAssignmentCompatible(
(Class<?>) parameterType,
argumentReader.getAssembledJavaType().getJavaTypeClass()
);
}
else {
final JavaType<?> argumentTypeDescriptor = creationState.getSqlAstCreationContext()
.getMappingMetamodel()
.getTypeConfiguration()
.getJavaTypeRegistry()
.resolveDescriptor( parameterType );
assignmentCompatible = areAssignmentCompatible(
argumentTypeDescriptor,
argumentReader.getAssembledJavaType()
);
}
if ( !assignmentCompatible ) {
if ( log.isDebugEnabled() ) {
log.debugf(
"Skipping constructor for dynamic-instantiation match due to argument mismatch [%s] : %s -> %s",
i,
argumentReader.getAssembledJavaType().getTypeName(),
parameterType.getTypeName()
);
}
continue constructor_loop;
}
}
constructor.setAccessible( true );
//noinspection rawtypes
return new DynamicInstantiationAssemblerConstructorImpl( constructor, javaType, argumentReaders );
}
}
if ( log.isDebugEnabled() ) {
log.debugf(
"Could not locate appropriate constructor for dynamic instantiation of [%s]; attempting bean-injection instantiation",
javaType.getJavaType().getTypeName()
);
}
if ( ! areAllArgumentsAliased ) {
throw new IllegalStateException(
"Cannot instantiate class '" + javaType.getJavaType().getTypeName() + "'"
+ " (it has no constructor with signature " + signature()
+ ", and not every argument has an alias)"
);
}
if ( !duplicatedAliases.isEmpty() ) {
throw new IllegalStateException(
"Cannot instantiate class '" + javaType.getJavaType().getTypeName() + "'"
+ " (it has no constructor with signature " + signature()
+ ", and has arguments with duplicate aliases ["
+ StringHelper.join( ",", duplicatedAliases ) + "])"
);
}
return new DynamicInstantiationAssemblerInjectionImpl<>( javaType, argumentReaders );
} }
} }
private DomainResultAssembler<R> assembler(
boolean areAllArgumentsAliased,
List<String> duplicatedAliases,
List<ArgumentReader<?>> argumentReaders,
AssemblerCreationState creationState) {
final List<Class<?>> argumentTypes =
argumentReaders.stream()
.map(reader -> reader.getAssembledJavaType().getJavaTypeClass())
.collect(toList());
final TypeConfiguration typeConfiguration =
creationState.getSqlAstCreationContext()
.getMappingMetamodel()
.getTypeConfiguration();
// find a constructor matching argument types
for ( Constructor<?> constructor : javaType.getJavaTypeClass().getDeclaredConstructors() ) {
if ( isConstructorCompatible( constructor, argumentTypes, typeConfiguration ) ) {
constructor.setAccessible( true );
@SuppressWarnings("unchecked")
final Constructor<R> construct = (Constructor<R>) constructor;
return new DynamicInstantiationAssemblerConstructorImpl<>( construct, javaType, argumentReaders );
}
}
if ( log.isDebugEnabled() ) {
log.debugf(
"Could not locate appropriate constructor for dynamic instantiation of [%s]; attempting bean-injection instantiation",
javaType.getJavaType().getTypeName()
);
}
if ( !areAllArgumentsAliased) {
throw new IllegalStateException(
"Cannot instantiate class '" + javaType.getJavaType().getTypeName() + "'"
+ " (it has no constructor with signature " + signature()
+ ", and not every argument has an alias)"
);
}
if ( !duplicatedAliases.isEmpty() ) {
throw new IllegalStateException(
"Cannot instantiate class '" + javaType.getJavaType().getTypeName() + "'"
+ " (it has no constructor with signature " + signature()
+ ", and has arguments with duplicate aliases ["
+ StringHelper.join( ",", duplicatedAliases) + "])"
);
}
return new DynamicInstantiationAssemblerInjectionImpl<>( javaType, argumentReaders );
}
private List<String> signature() { private List<String> signature() {
return argumentResults.stream() return argumentResults.stream()
.map( adt -> adt.getResultJavaType().getJavaType().getTypeName() ) .map( adt -> adt.getResultJavaType().getJavaType().getTypeName() )

View File

@ -6,12 +6,56 @@
*/ */
package org.hibernate.sql.results.graph.instantiation.internal; package org.hibernate.sql.results.graph.instantiation.internal;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.List;
import static org.hibernate.query.sqm.tree.expression.Compatibility.areAssignmentCompatible;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
* @author Gavin King
*/ */
public class InstantiationHelper { public class InstantiationHelper {
private static final Logger log = Logger.getLogger( InstantiationHelper.class );
private InstantiationHelper() { private InstantiationHelper() {
// disallow direct instantiation // disallow direct instantiation
} }
public static boolean isConstructorCompatible(
Constructor<?> constructor,
List<Class<?>> argumentTypes,
TypeConfiguration typeConfiguration) {
final Type[] genericParameterTypes = constructor.getGenericParameterTypes();
if ( genericParameterTypes.length == argumentTypes.size() ) {
for (int i = 0; i < argumentTypes.size(); i++ ) {
final Type parameterType = genericParameterTypes[i];
final Class<?> argumentType = argumentTypes.get( i );
final Class<?> argType = parameterType instanceof Class<?>
? (Class<?>) parameterType
: typeConfiguration.getJavaTypeRegistry().resolveDescriptor( parameterType ).getJavaTypeClass();
if ( !areAssignmentCompatible( argType, argumentType ) ) {
if ( log.isDebugEnabled() ) {
log.debugf(
"Skipping constructor for dynamic-instantiation match due to argument mismatch [%s] : %s -> %s",
i,
argumentType.getTypeName(),
parameterType.getTypeName()
);
}
return false;
}
}
return true;
}
else {
return false;
}
}
} }

View File

@ -115,7 +115,7 @@ public class EnumType<T extends Enum<T>>
if ( parameters.containsKey( ENUM ) ) { if ( parameters.containsKey( ENUM ) ) {
final String enumClassName = (String) parameters.get( ENUM ); final String enumClassName = (String) parameters.get( ENUM );
try { try {
enumClass = ReflectHelper.classForName( enumClassName, this.getClass() ).asSubclass( Enum.class ); enumClass = (Class<T>) ReflectHelper.classForName( enumClassName, this.getClass() ).asSubclass( Enum.class );
} }
catch ( ClassNotFoundException exception ) { catch ( ClassNotFoundException exception ) {
throw new HibernateException("Enum class not found: " + enumClassName, exception); throw new HibernateException("Enum class not found: " + enumClassName, exception);

View File

@ -83,7 +83,7 @@ public class SerializableToBlobType<T extends Serializable> implements BasicType
} }
try { try {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Class<T> classForName = ReflectHelper.classForName(className); Class<T> classForName = (Class<T>) ReflectHelper.classForName(className);
setJavaTypeDescriptor( new SerializableJavaType<>(classForName) ); setJavaTypeDescriptor( new SerializableJavaType<>(classForName) );
} }
catch ( ClassNotFoundException e ) { catch ( ClassNotFoundException e ) {

View File

@ -3071,7 +3071,8 @@ public abstract class AbstractQueryCacheResultTransformerTest {
private Constructor getConstructor() { private Constructor getConstructor() {
Type studentNametype = Type studentNametype =
scope.getSessionFactory().getMappingMetamodel().getEntityDescriptor( Student.class.getName() ) scope.getSessionFactory().getMappingMetamodel()
.getEntityDescriptor( Student.class.getName() )
.getPropertyType( "name" ); .getPropertyType( "name" );
return ReflectHelper.getConstructor( return ReflectHelper.getConstructor(
Student.class, Student.class,

View File

@ -10,7 +10,6 @@ import java.lang.reflect.Constructor;
import java.sql.Connection; import java.sql.Connection;
import java.sql.Driver; import java.sql.Driver;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties; import java.util.Properties;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -42,7 +41,7 @@ public final class DialectContext {
final Constructor<? extends Dialect> constructor; final Constructor<? extends Dialect> constructor;
try { try {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final Class<? extends Dialect> dialectClass = ReflectHelper.classForName( dialectName ); final Class<? extends Dialect> dialectClass = (Class<? extends Dialect>) ReflectHelper.classForName( dialectName );
constructor = dialectClass.getConstructor( DialectResolutionInfo.class ); constructor = dialectClass.getConstructor( DialectResolutionInfo.class );
} }
catch (ClassNotFoundException cnfe) { catch (ClassNotFoundException cnfe) {

View File

@ -84,7 +84,7 @@ public class Validation {
int errorOffset, int errorOffset,
HqlParser.StatementContext statementContext) { HqlParser.StatementContext statementContext) {
try { try {
return createSemanticQueryBuilder( returnType, factory ).visitStatement( statementContext ); return createSemanticQueryBuilder( returnType, hql, factory ).visitStatement( statementContext );
} }
catch ( JdbcTypeRecommendationException ignored ) { catch ( JdbcTypeRecommendationException ignored ) {
// just squash these for now // just squash these for now
@ -100,15 +100,15 @@ public class Validation {
} }
private static SemanticQueryBuilder<?> createSemanticQueryBuilder( private static SemanticQueryBuilder<?> createSemanticQueryBuilder(
@Nullable TypeMirror returnType, SessionFactoryImplementor factory) { @Nullable TypeMirror returnType, String hql, SessionFactoryImplementor factory) {
if ( returnType != null && returnType.getKind() == TypeKind.DECLARED ) { if ( returnType != null && returnType.getKind() == TypeKind.DECLARED ) {
final DeclaredType declaredType = (DeclaredType) returnType; final DeclaredType declaredType = (DeclaredType) returnType;
final TypeElement typeElement = (TypeElement) declaredType.asElement(); final TypeElement typeElement = (TypeElement) declaredType.asElement();
if ( isEntity( typeElement ) ) { if ( isEntity( typeElement ) ) {
return new SemanticQueryBuilder<>( getEntityName( typeElement ), () -> false, factory ); return new SemanticQueryBuilder<>( getEntityName( typeElement ), () -> false, factory, hql );
} }
} }
return new SemanticQueryBuilder<>( Object[].class, () -> false, factory ); return new SemanticQueryBuilder<>( Object[].class, () -> false, factory, hql );
} }
private static HqlParser.StatementContext parseAndCheckSyntax(String hql, Handler handler) { private static HqlParser.StatementContext parseAndCheckSyntax(String hql, Handler handler) {