make fully-qualified enum literals in @Query pass the validation
JD examples and TCK require this, though it's not really correct Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
0e9da568c8
commit
8caa7096fb
|
@ -19,6 +19,7 @@ import org.hibernate.graph.spi.RootGraphImplementor;
|
|||
import org.hibernate.jpa.spi.JpaCompliance;
|
||||
import org.hibernate.metamodel.MappingMetamodel;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.type.descriptor.java.EnumJavaType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
|
@ -85,6 +86,10 @@ public interface JpaMetamodel extends Metamodel {
|
|||
*/
|
||||
Map<String, Map<Class<?>, Enum<?>>> getAllowedEnumLiteralTexts();
|
||||
|
||||
EnumJavaType<?> getEnumType(String prefix);
|
||||
|
||||
<E extends Enum<E>> E enumValue(EnumJavaType<E> enumType, String terminal);
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Covariant returns
|
||||
|
||||
|
|
|
@ -243,6 +243,28 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
return allowedEnumLiteralTexts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumJavaType<?> getEnumType(String prefix) {
|
||||
try {
|
||||
final Class<?> namedClass =
|
||||
getServiceRegistry().requireService( ClassLoaderService.class )
|
||||
.classForName( prefix );
|
||||
if ( namedClass != null && namedClass.isEnum() ) {
|
||||
return (EnumJavaType) getTypeConfiguration()
|
||||
.getJavaTypeRegistry()
|
||||
.resolveDescriptor(namedClass);
|
||||
}
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E extends Enum<E>> E enumValue(EnumJavaType<E> enumType, String terminal) {
|
||||
return Enum.valueOf( enumType.getJavaTypeClass(), terminal );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void addNamedEntityGraph(String graphName, RootGraphImplementor<T> entityGraph) {
|
||||
final EntityGraph<?> old = entityGraphMap.put(
|
||||
|
|
|
@ -72,6 +72,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup;
|
|||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.ComponentType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.descriptor.java.EnumJavaType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
@ -523,6 +524,16 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
|
|||
return jpaMetamodel.getAllowedEnumLiteralTexts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumJavaType<?> getEnumType(String className) {
|
||||
return jpaMetamodel.getEnumType(className);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E extends Enum<E>> E enumValue(EnumJavaType<E> enumType, String terminal) {
|
||||
return jpaMetamodel.enumValue(enumType, terminal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getImplementors(String className) throws MappingException {
|
||||
// computeIfAbsent() can be a contention point and we expect all the values to be in the map at some point so
|
||||
|
|
|
@ -10,12 +10,14 @@ import java.lang.reflect.Field;
|
|||
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.hql.HqlLogging;
|
||||
import org.hibernate.query.hql.spi.DotIdentifierConsumer;
|
||||
import org.hibernate.query.hql.spi.SemanticPathPart;
|
||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||
import org.hibernate.query.hql.spi.SqmPathRegistry;
|
||||
import org.hibernate.query.sqm.NodeBuilder;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.spi.SqmCreationContext;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
|
@ -26,7 +28,6 @@ import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
|
|||
import org.hibernate.query.sqm.tree.from.SqmFrom;
|
||||
import org.hibernate.type.descriptor.java.EnumJavaType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
|
||||
|
||||
/**
|
||||
* @asciidoc
|
||||
|
@ -177,17 +178,20 @@ public class BasicDotIdentifierConsumer implements DotIdentifierConsumer {
|
|||
}
|
||||
|
||||
final String path = pathSoFar.toString();
|
||||
final String importableName = creationContext.getJpaMetamodel().qualifyImportableName( path );
|
||||
final JpaMetamodelImplementor jpaMetamodel = creationContext.getJpaMetamodel();
|
||||
final String importableName = jpaMetamodel.qualifyImportableName( path );
|
||||
final NodeBuilder nodeBuilder = creationContext.getNodeBuilder();
|
||||
if ( importableName != null ) {
|
||||
final EntityDomainType<?> entityDomainType = creationContext.getJpaMetamodel().entity( importableName );
|
||||
final EntityDomainType<?> entityDomainType = jpaMetamodel.entity( importableName );
|
||||
if ( entityDomainType != null ) {
|
||||
return new SqmLiteralEntityType( entityDomainType, creationContext.getNodeBuilder() );
|
||||
return new SqmLiteralEntityType( entityDomainType, nodeBuilder );
|
||||
}
|
||||
}
|
||||
|
||||
final SqmFunctionDescriptor functionDescriptor = creationContext.getQueryEngine()
|
||||
.getSqmFunctionRegistry()
|
||||
.findFunctionDescriptor( path );
|
||||
final SqmFunctionDescriptor functionDescriptor =
|
||||
creationContext.getQueryEngine()
|
||||
.getSqmFunctionRegistry()
|
||||
.findFunctionDescriptor( path );
|
||||
if ( functionDescriptor != null ) {
|
||||
return functionDescriptor.generateSqmExpression(
|
||||
null,
|
||||
|
@ -195,55 +199,37 @@ public class BasicDotIdentifierConsumer implements DotIdentifierConsumer {
|
|||
);
|
||||
}
|
||||
|
||||
// // see if it is a Class name...
|
||||
// try {
|
||||
// final Class<?> namedClass = creationState.getCreationContext()
|
||||
// .getServiceRegistry()
|
||||
// .getService( ClassLoaderService.class )
|
||||
// .classForName( pathSoFar );
|
||||
// if ( namedClass != null ) {
|
||||
// return new
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ignore) {
|
||||
// }
|
||||
|
||||
// see if it is a named field/enum reference
|
||||
final int splitPosition = path.lastIndexOf( '.' );
|
||||
if ( splitPosition > 0 ) {
|
||||
final String prefix = path.substring( 0, splitPosition );
|
||||
final String terminal = path.substring( splitPosition + 1 );
|
||||
|
||||
//TODO: try interpreting paths of form foo.bar.Foo.Bar as foo.bar.Foo$Bar
|
||||
final EnumJavaType<?> enumType = jpaMetamodel.getEnumType(prefix);
|
||||
if ( enumType != null ) {
|
||||
return new SqmEnumLiteral(
|
||||
jpaMetamodel.enumValue(enumType, terminal),
|
||||
enumType,
|
||||
terminal,
|
||||
nodeBuilder
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
final Class<?> namedClass = creationContext
|
||||
.getServiceRegistry()
|
||||
.requireService( ClassLoaderService.class )
|
||||
.classForName( prefix );
|
||||
final Class<?> namedClass =
|
||||
creationContext.getServiceRegistry()
|
||||
.requireService( ClassLoaderService.class )
|
||||
.classForName( prefix );
|
||||
if ( namedClass != null ) {
|
||||
final JavaTypeRegistry javaTypeRegistry = creationContext.getJpaMetamodel()
|
||||
.getTypeConfiguration()
|
||||
.getJavaTypeRegistry();
|
||||
|
||||
if ( namedClass.isEnum() ) {
|
||||
return new SqmEnumLiteral(
|
||||
Enum.valueOf( (Class) namedClass, terminal ),
|
||||
(EnumJavaType) javaTypeRegistry.resolveDescriptor( namedClass ),
|
||||
terminal,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
final Field referencedField = namedClass.getDeclaredField( terminal );
|
||||
if ( referencedField != null ) {
|
||||
final JavaType<?> fieldJtd = javaTypeRegistry
|
||||
.getDescriptor( referencedField.getType() );
|
||||
//noinspection unchecked
|
||||
return new SqmFieldLiteral( referencedField, fieldJtd, creationContext.getNodeBuilder() );
|
||||
}
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
final Field referencedField = namedClass.getDeclaredField( terminal );
|
||||
if ( referencedField != null ) {
|
||||
final JavaType<?> fieldJtd =
|
||||
jpaMetamodel
|
||||
.getTypeConfiguration()
|
||||
.getJavaTypeRegistry()
|
||||
.getDescriptor( referencedField.getType() );
|
||||
return new SqmFieldLiteral( referencedField, fieldJtd, nodeBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.hibernate.processor.test.data;
|
||||
package org.hibernate.processor.test.data.basic;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
|
@ -1,4 +1,4 @@
|
|||
package org.hibernate.processor.test.data;
|
||||
package org.hibernate.processor.test.data.basic;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import org.hibernate.annotations.NaturalId;
|
|
@ -1,4 +1,4 @@
|
|||
package org.hibernate.processor.test.data;
|
||||
package org.hibernate.processor.test.data.basic;
|
||||
|
||||
import jakarta.data.Limit;
|
||||
import jakarta.data.Order;
|
||||
|
@ -22,7 +22,6 @@ import java.math.BigDecimal;
|
|||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Repository(dataStore = "myds")
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.processor.test.data;
|
||||
package org.hibernate.processor.test.data.basic;
|
||||
|
||||
import org.hibernate.processor.test.util.CompilationTest;
|
||||
import org.hibernate.processor.test.util.WithClasses;
|
|
@ -102,4 +102,7 @@ public interface Library {
|
|||
|
||||
@Find
|
||||
List<Author> authorsByCityAndPostcode(String address_city, String address_postcode);
|
||||
|
||||
@Query("where type = org.hibernate.processor.test.data.eg.Type.Magazine")
|
||||
List<Book> magazines();
|
||||
}
|
||||
|
|
|
@ -108,6 +108,7 @@ import org.hibernate.type.MapType;
|
|||
import org.hibernate.type.SetType;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.descriptor.java.EnumJavaType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.java.spi.UnknownBasicJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
|
@ -283,6 +284,8 @@ public abstract class MockSessionFactory
|
|||
|
||||
abstract boolean isClassDefined(String qualifiedName);
|
||||
|
||||
abstract boolean isEnum(String className);
|
||||
|
||||
abstract boolean isFieldDefined(String qualifiedClassName, String fieldName);
|
||||
|
||||
abstract boolean isConstructorDefined(String qualifiedClassName, List<Type> argumentTypes);
|
||||
|
@ -818,6 +821,26 @@ public abstract class MockSessionFactory
|
|||
throw new UnsupportedOperationException("operation not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumJavaType<?> getEnumType(String className) {
|
||||
if ( isEnum(className) ) {
|
||||
return new EnumJavaType( Enum.class ) {
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return className;
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E extends Enum<E>> E enumValue(EnumJavaType<E> enumType, String terminal) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaCompliance getJpaCompliance() {
|
||||
return jpaCompliance;
|
||||
|
|
|
@ -563,6 +563,12 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isEnum(String className) {
|
||||
final TypeElement typeElement = elementUtil.getTypeElement(className);
|
||||
return typeElement != null && typeElement.getKind() == ElementKind.ENUM;
|
||||
}
|
||||
|
||||
private static boolean isEmbeddableType(TypeElement type) {
|
||||
return hasAnnotation(type, "Embeddable");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue