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:
parent
0bce456e3a
commit
24937b4e67
|
@ -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();
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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] );
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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() );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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() )
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 ) {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue