HHH 18705 - Hibernate processor creates bad TypedReferenceQuery when @Entity have name attribute (#9064)
- entityType moved into org.hibernate.processor.Context - result/type(returnType) moved into new utility class org.hibernate.processor.util.SqmTypeUtils
This commit is contained in:
parent
d6e1c9b2a8
commit
b1ee3d4334
|
@ -17,6 +17,7 @@ import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.AnnotationValue;
|
import javax.lang.model.element.AnnotationValue;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.lang.model.element.ModuleElement;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
import javax.lang.model.type.TypeKind;
|
import javax.lang.model.type.TypeKind;
|
||||||
|
@ -34,6 +35,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import static java.lang.Boolean.parseBoolean;
|
import static java.lang.Boolean.parseBoolean;
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY;
|
import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY;
|
||||||
|
import static org.hibernate.processor.validation.ProcessorSessionFactory.findEntityByUnqualifiedName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Max Andersen
|
* @author Max Andersen
|
||||||
|
@ -505,4 +507,26 @@ public final class Context {
|
||||||
public void addEnumValue(String type, String value) {
|
public void addEnumValue(String type, String value) {
|
||||||
enumTypesByValue.computeIfAbsent( value, s -> new TreeSet<>() ).add( type );
|
enumTypesByValue.computeIfAbsent( value, s -> new TreeSet<>() ).add( type );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public TypeElement entityType(String entityName) {
|
||||||
|
final Elements elementUtils = getElementUtils();
|
||||||
|
final String qualifiedName = qualifiedNameForEntityName(entityName);
|
||||||
|
if ( qualifiedName != null ) {
|
||||||
|
return elementUtils.getTypeElement(qualifiedName);
|
||||||
|
}
|
||||||
|
TypeElement symbol =
|
||||||
|
findEntityByUnqualifiedName( entityName,
|
||||||
|
elementUtils.getModuleElement("") );
|
||||||
|
if ( symbol != null ) {
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
for ( ModuleElement module : elementUtils.getAllModuleElements() ) {
|
||||||
|
symbol = findEntityByUnqualifiedName( entityName, module );
|
||||||
|
if ( symbol != null ) {
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,7 @@ import org.hibernate.processor.model.Metamodel;
|
||||||
import org.hibernate.processor.util.Constants;
|
import org.hibernate.processor.util.Constants;
|
||||||
import org.hibernate.processor.validation.ProcessorSessionFactory;
|
import org.hibernate.processor.validation.ProcessorSessionFactory;
|
||||||
import org.hibernate.processor.validation.Validation;
|
import org.hibernate.processor.validation.Validation;
|
||||||
import org.hibernate.query.criteria.JpaEntityJoin;
|
|
||||||
import org.hibernate.query.criteria.JpaRoot;
|
|
||||||
import org.hibernate.query.criteria.JpaSelection;
|
|
||||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
|
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||||
|
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
|
@ -33,6 +29,7 @@ import static org.hibernate.processor.util.Constants.TYPED_QUERY_REFERENCE;
|
||||||
import static org.hibernate.processor.util.TypeUtils.containsAnnotation;
|
import static org.hibernate.processor.util.TypeUtils.containsAnnotation;
|
||||||
import static org.hibernate.processor.util.TypeUtils.getAnnotationMirror;
|
import static org.hibernate.processor.util.TypeUtils.getAnnotationMirror;
|
||||||
import static org.hibernate.processor.util.TypeUtils.getAnnotationValue;
|
import static org.hibernate.processor.util.TypeUtils.getAnnotationValue;
|
||||||
|
import static org.hibernate.processor.util.SqmTypeUtils.resultType;
|
||||||
|
|
||||||
public abstract class AnnotationMeta implements Metamodel {
|
public abstract class AnnotationMeta implements Metamodel {
|
||||||
|
|
||||||
|
@ -126,7 +123,7 @@ public abstract class AnnotationMeta implements Metamodel {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ( getAnnotationValue( mirror, "resultClass" ) == null ) {
|
if ( getAnnotationValue( mirror, "resultClass" ) == null ) {
|
||||||
final String resultType = resultType( selectStatement );
|
final String resultType = resultType( selectStatement, context );
|
||||||
if ( resultType != null ) {
|
if ( resultType != null ) {
|
||||||
putMember( "QUERY_" + name,
|
putMember( "QUERY_" + name,
|
||||||
new TypedMetaAttribute( this, name, "QUERY_", resultType,
|
new TypedMetaAttribute( this, name, "QUERY_", resultType,
|
||||||
|
@ -139,27 +136,6 @@ public abstract class AnnotationMeta implements Metamodel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @Nullable String resultType(SqmSelectStatement<?> selectStatement) {
|
|
||||||
final JpaSelection<?> selection = selectStatement.getSelection();
|
|
||||||
if (selection == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else if (selection instanceof SqmSelectClause from) {
|
|
||||||
return from.getSelectionItems().size() > 1
|
|
||||||
? "Object[]"
|
|
||||||
: from.getSelectionItems().get(0).getJavaTypeName();
|
|
||||||
}
|
|
||||||
else if (selection instanceof JpaRoot<?> root) {
|
|
||||||
return root.getModel().getTypeName();
|
|
||||||
}
|
|
||||||
else if (selection instanceof JpaEntityJoin<?, ?> join) {
|
|
||||||
return join.getModel().getTypeName();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return selection.getJavaTypeName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isQueryMethodName(String name) {
|
private static boolean isQueryMethodName(String name) {
|
||||||
return name.length() >= 2
|
return name.length() >= 2
|
||||||
&& name.charAt(0) == '#'
|
&& name.charAt(0) == '#'
|
||||||
|
|
|
@ -5,24 +5,17 @@
|
||||||
package org.hibernate.processor.annotation;
|
package org.hibernate.processor.annotation;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.hibernate.processor.Context;
|
|
||||||
import org.hibernate.processor.model.MetaAttribute;
|
import org.hibernate.processor.model.MetaAttribute;
|
||||||
import org.hibernate.processor.model.Metamodel;
|
import org.hibernate.processor.model.Metamodel;
|
||||||
import org.hibernate.processor.util.Constants;
|
import org.hibernate.processor.util.Constants;
|
||||||
import org.hibernate.query.sqm.SqmExpressible;
|
import org.hibernate.query.sqm.SqmExpressible;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
|
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
|
||||||
|
|
||||||
import javax.lang.model.element.ModuleElement;
|
|
||||||
import javax.lang.model.element.TypeElement;
|
|
||||||
import javax.lang.model.util.Elements;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
import static org.hibernate.processor.util.StringUtil.nameToFieldName;
|
import static org.hibernate.processor.util.StringUtil.nameToFieldName;
|
||||||
import static org.hibernate.processor.validation.ProcessorSessionFactory.findEntityByUnqualifiedName;
|
import static org.hibernate.processor.util.SqmTypeUtils.resultType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
|
@ -96,27 +89,6 @@ class NamedQueryMethod implements MetaAttribute {
|
||||||
return "QUERY_" + nameToFieldName(name);
|
return "QUERY_" + nameToFieldName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String returnType() {
|
|
||||||
final JavaType<?> javaType = select.getSelection().getJavaTypeDescriptor();
|
|
||||||
if ( javaType != null ) {
|
|
||||||
return javaType.getTypeName();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final List<SqmSelectableNode<?>> items =
|
|
||||||
select.getQuerySpec().getSelectClause().getSelectionItems();
|
|
||||||
final SqmExpressible<?> expressible;
|
|
||||||
if ( items.size() == 1 && ( expressible = items.get( 0 ).getExpressible() ) != null ) {
|
|
||||||
final String typeName = expressible.getTypeName();
|
|
||||||
final TypeElement entityType = entityType( typeName );
|
|
||||||
return entityType == null ? typeName : entityType.getQualifiedName().toString();
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "Object[]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void notNull(StringBuilder declaration) {
|
void notNull(StringBuilder declaration) {
|
||||||
if ( addNonnullAnnotation ) {
|
if ( addNonnullAnnotation ) {
|
||||||
declaration
|
declaration
|
||||||
|
@ -149,7 +121,7 @@ class NamedQueryMethod implements MetaAttribute {
|
||||||
declaration
|
declaration
|
||||||
.append(annotationMeta.importType(Constants.LIST))
|
.append(annotationMeta.importType(Constants.LIST))
|
||||||
.append('<')
|
.append('<')
|
||||||
.append(annotationMeta.importType(returnType()))
|
.append( annotationMeta.importType( resultType( select, annotationMeta.getContext() ) ) )
|
||||||
.append("> ")
|
.append("> ")
|
||||||
.append(name);
|
.append(name);
|
||||||
if ( reactive ) {
|
if ( reactive ) {
|
||||||
|
@ -193,28 +165,6 @@ class NamedQueryMethod implements MetaAttribute {
|
||||||
return "unknown".equals(paramType) ? "Object" : annotationMeta.importType(paramType);
|
return "unknown".equals(paramType) ? "Object" : annotationMeta.importType(paramType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable TypeElement entityType(String entityName) {
|
|
||||||
final Context context = annotationMeta.getContext();
|
|
||||||
final Elements elementUtils = context.getElementUtils();
|
|
||||||
final String qualifiedName = context.qualifiedNameForEntityName(entityName);
|
|
||||||
if ( qualifiedName != null ) {
|
|
||||||
return elementUtils.getTypeElement(qualifiedName);
|
|
||||||
}
|
|
||||||
TypeElement symbol =
|
|
||||||
findEntityByUnqualifiedName( entityName,
|
|
||||||
elementUtils.getModuleElement("") );
|
|
||||||
if ( symbol != null ) {
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
for ( ModuleElement module : elementUtils.getAllModuleElements() ) {
|
|
||||||
symbol = findEntityByUnqualifiedName( entityName, module );
|
|
||||||
if ( symbol != null ) {
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAttributeNameDeclarationString() {
|
public String getAttributeNameDeclarationString() {
|
||||||
throw new UnsupportedOperationException("operation not supported");
|
throw new UnsupportedOperationException("operation not supported");
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.processor.util;
|
||||||
|
|
||||||
|
import org.hibernate.processor.Context;
|
||||||
|
import org.hibernate.query.sqm.SqmExpressible;
|
||||||
|
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||||
|
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
|
||||||
|
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class SqmTypeUtils {
|
||||||
|
private SqmTypeUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String resultType(SqmSelectStatement<?> selectStatement, Context context) {
|
||||||
|
final String javaTypeName = selectStatement.getSelection().getJavaTypeName();
|
||||||
|
if ( javaTypeName != null ) {
|
||||||
|
return javaTypeName;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final List<SqmSelectableNode<?>> items =
|
||||||
|
selectStatement.getQuerySpec().getSelectClause().getSelectionItems();
|
||||||
|
final SqmExpressible<?> expressible;
|
||||||
|
if ( items.size() == 1 && (expressible = items.get( 0 ).getExpressible()) != null ) {
|
||||||
|
final String typeName = expressible.getTypeName();
|
||||||
|
final TypeElement entityType = context.entityType( typeName );
|
||||||
|
return entityType == null ? typeName : entityType.getQualifiedName().toString();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "Object[]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.processor.test.namedentity;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.NamedQuery;
|
||||||
|
|
||||||
|
@Entity(name = "Liber")
|
||||||
|
@NamedQuery(name = "findAllBooks", query = "from Liber")
|
||||||
|
public class Book {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.processor.test.namedentity;
|
||||||
|
|
||||||
|
import jakarta.persistence.TypedQueryReference;
|
||||||
|
import org.hibernate.processor.test.util.CompilationTest;
|
||||||
|
import org.hibernate.processor.test.util.WithClasses;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
import static org.hibernate.processor.test.util.TestUtil.assertMetamodelClassGeneratedFor;
|
||||||
|
import static org.hibernate.processor.test.util.TestUtil.assertPresenceOfFieldInMetamodelFor;
|
||||||
|
import static org.hibernate.processor.test.util.TestUtil.getFieldFromMetamodelFor;
|
||||||
|
import static org.hibernate.processor.test.util.TestUtil.getMetaModelSourceAsString;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class NamedEntityTest extends CompilationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithClasses(Book.class)
|
||||||
|
public void test() {
|
||||||
|
System.out.println( getMetaModelSourceAsString( Book.class ) );
|
||||||
|
|
||||||
|
assertMetamodelClassGeneratedFor( Book.class );
|
||||||
|
|
||||||
|
assertPresenceOfFieldInMetamodelFor( Book.class, "QUERY_FIND_ALL_BOOKS" );
|
||||||
|
final Field field = getFieldFromMetamodelFor( Book.class, "_findAllBooks_" );
|
||||||
|
assertEquals( TypedQueryReference.class, field.getType() );
|
||||||
|
final Type genericType = field.getGenericType();
|
||||||
|
assertTrue( genericType instanceof ParameterizedType );
|
||||||
|
final ParameterizedType parameterizedType = (ParameterizedType) genericType;
|
||||||
|
assertEquals( Book.class, parameterizedType.getActualTypeArguments()[0] );
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue