Skip to content

Commit b1ee3d4

Browse files
authored
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
1 parent d6e1c9b commit b1ee3d4

File tree

6 files changed

+124
-78
lines changed

6 files changed

+124
-78
lines changed

tooling/metamodel-generator/src/main/java/org/hibernate/processor/Context.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import javax.lang.model.element.AnnotationValue;
1818
import javax.lang.model.element.Element;
1919
import javax.lang.model.element.ExecutableElement;
20+
import javax.lang.model.element.ModuleElement;
2021
import javax.lang.model.element.TypeElement;
2122
import javax.lang.model.type.DeclaredType;
2223
import javax.lang.model.type.TypeKind;
@@ -34,6 +35,7 @@
3435
import static java.lang.Boolean.parseBoolean;
3536
import static java.util.Collections.emptyList;
3637
import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY;
38+
import static org.hibernate.processor.validation.ProcessorSessionFactory.findEntityByUnqualifiedName;
3739

3840
/**
3941
* @author Max Andersen
@@ -505,4 +507,26 @@ public Map<String,Set<String>> getEnumTypesByValue() {
505507
public void addEnumValue(String type, String value) {
506508
enumTypesByValue.computeIfAbsent( value, s -> new TreeSet<>() ).add( type );
507509
}
510+
511+
@Nullable
512+
public TypeElement entityType(String entityName) {
513+
final Elements elementUtils = getElementUtils();
514+
final String qualifiedName = qualifiedNameForEntityName(entityName);
515+
if ( qualifiedName != null ) {
516+
return elementUtils.getTypeElement(qualifiedName);
517+
}
518+
TypeElement symbol =
519+
findEntityByUnqualifiedName( entityName,
520+
elementUtils.getModuleElement("") );
521+
if ( symbol != null ) {
522+
return symbol;
523+
}
524+
for ( ModuleElement module : elementUtils.getAllModuleElements() ) {
525+
symbol = findEntityByUnqualifiedName( entityName, module );
526+
if ( symbol != null ) {
527+
return symbol;
528+
}
529+
}
530+
return null;
531+
}
508532
}

tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMeta.java

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,7 @@
1313
import org.hibernate.processor.util.Constants;
1414
import org.hibernate.processor.validation.ProcessorSessionFactory;
1515
import org.hibernate.processor.validation.Validation;
16-
import org.hibernate.query.criteria.JpaEntityJoin;
17-
import org.hibernate.query.criteria.JpaRoot;
18-
import org.hibernate.query.criteria.JpaSelection;
1916
import org.hibernate.query.sqm.tree.SqmStatement;
20-
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
2117
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
2218

2319
import javax.lang.model.element.AnnotationMirror;
@@ -33,6 +29,7 @@
3329
import static org.hibernate.processor.util.TypeUtils.containsAnnotation;
3430
import static org.hibernate.processor.util.TypeUtils.getAnnotationMirror;
3531
import static org.hibernate.processor.util.TypeUtils.getAnnotationValue;
32+
import static org.hibernate.processor.util.SqmTypeUtils.resultType;
3633

3734
public abstract class AnnotationMeta implements Metamodel {
3835

@@ -126,7 +123,7 @@ private void handleNamedQuery(AnnotationMirror mirror, boolean checkHql) {
126123
);
127124
}
128125
if ( getAnnotationValue( mirror, "resultClass" ) == null ) {
129-
final String resultType = resultType( selectStatement );
126+
final String resultType = resultType( selectStatement, context );
130127
if ( resultType != null ) {
131128
putMember( "QUERY_" + name,
132129
new TypedMetaAttribute( this, name, "QUERY_", resultType,
@@ -139,27 +136,6 @@ private void handleNamedQuery(AnnotationMirror mirror, boolean checkHql) {
139136
}
140137
}
141138

142-
private static @Nullable String resultType(SqmSelectStatement<?> selectStatement) {
143-
final JpaSelection<?> selection = selectStatement.getSelection();
144-
if (selection == null) {
145-
return null;
146-
}
147-
else if (selection instanceof SqmSelectClause from) {
148-
return from.getSelectionItems().size() > 1
149-
? "Object[]"
150-
: from.getSelectionItems().get(0).getJavaTypeName();
151-
}
152-
else if (selection instanceof JpaRoot<?> root) {
153-
return root.getModel().getTypeName();
154-
}
155-
else if (selection instanceof JpaEntityJoin<?, ?> join) {
156-
return join.getModel().getTypeName();
157-
}
158-
else {
159-
return selection.getJavaTypeName();
160-
}
161-
}
162-
163139
private static boolean isQueryMethodName(String name) {
164140
return name.length() >= 2
165141
&& name.charAt(0) == '#'

tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/NamedQueryMethod.java

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,17 @@
55
package org.hibernate.processor.annotation;
66

77
import org.checkerframework.checker.nullness.qual.Nullable;
8-
import org.hibernate.processor.Context;
98
import org.hibernate.processor.model.MetaAttribute;
109
import org.hibernate.processor.model.Metamodel;
1110
import org.hibernate.processor.util.Constants;
1211
import org.hibernate.query.sqm.SqmExpressible;
1312
import org.hibernate.query.sqm.tree.expression.SqmParameter;
1413
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
15-
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
16-
import org.hibernate.type.descriptor.java.JavaType;
1714

18-
import javax.lang.model.element.ModuleElement;
19-
import javax.lang.model.element.TypeElement;
20-
import javax.lang.model.util.Elements;
21-
import java.util.List;
2215
import java.util.TreeSet;
2316

2417
import static org.hibernate.processor.util.StringUtil.nameToFieldName;
25-
import static org.hibernate.processor.validation.ProcessorSessionFactory.findEntityByUnqualifiedName;
18+
import static org.hibernate.processor.util.SqmTypeUtils.resultType;
2619

2720
/**
2821
* @author Gavin King
@@ -96,27 +89,6 @@ private String fieldName() {
9689
return "QUERY_" + nameToFieldName(name);
9790
}
9891

99-
private String returnType() {
100-
final JavaType<?> javaType = select.getSelection().getJavaTypeDescriptor();
101-
if ( javaType != null ) {
102-
return javaType.getTypeName();
103-
}
104-
else {
105-
final List<SqmSelectableNode<?>> items =
106-
select.getQuerySpec().getSelectClause().getSelectionItems();
107-
final SqmExpressible<?> expressible;
108-
if ( items.size() == 1 && ( expressible = items.get( 0 ).getExpressible() ) != null ) {
109-
final String typeName = expressible.getTypeName();
110-
final TypeElement entityType = entityType( typeName );
111-
return entityType == null ? typeName : entityType.getQualifiedName().toString();
112-
113-
}
114-
else {
115-
return "Object[]";
116-
}
117-
}
118-
}
119-
12092
void notNull(StringBuilder declaration) {
12193
if ( addNonnullAnnotation ) {
12294
declaration
@@ -149,7 +121,7 @@ private void returnType(StringBuilder declaration) {
149121
declaration
150122
.append(annotationMeta.importType(Constants.LIST))
151123
.append('<')
152-
.append(annotationMeta.importType(returnType()))
124+
.append( annotationMeta.importType( resultType( select, annotationMeta.getContext() ) ) )
153125
.append("> ")
154126
.append(name);
155127
if ( reactive ) {
@@ -193,28 +165,6 @@ private String parameterType(SqmParameter<?> param) {
193165
return "unknown".equals(paramType) ? "Object" : annotationMeta.importType(paramType);
194166
}
195167

196-
private @Nullable TypeElement entityType(String entityName) {
197-
final Context context = annotationMeta.getContext();
198-
final Elements elementUtils = context.getElementUtils();
199-
final String qualifiedName = context.qualifiedNameForEntityName(entityName);
200-
if ( qualifiedName != null ) {
201-
return elementUtils.getTypeElement(qualifiedName);
202-
}
203-
TypeElement symbol =
204-
findEntityByUnqualifiedName( entityName,
205-
elementUtils.getModuleElement("") );
206-
if ( symbol != null ) {
207-
return symbol;
208-
}
209-
for ( ModuleElement module : elementUtils.getAllModuleElements() ) {
210-
symbol = findEntityByUnqualifiedName( entityName, module );
211-
if ( symbol != null ) {
212-
return symbol;
213-
}
214-
}
215-
return null;
216-
}
217-
218168
@Override
219169
public String getAttributeNameDeclarationString() {
220170
throw new UnsupportedOperationException("operation not supported");
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.processor.util;
6+
7+
import org.hibernate.processor.Context;
8+
import org.hibernate.query.sqm.SqmExpressible;
9+
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
10+
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
11+
12+
import javax.lang.model.element.TypeElement;
13+
import java.util.List;
14+
15+
public final class SqmTypeUtils {
16+
private SqmTypeUtils() {
17+
}
18+
19+
public static String resultType(SqmSelectStatement<?> selectStatement, Context context) {
20+
final String javaTypeName = selectStatement.getSelection().getJavaTypeName();
21+
if ( javaTypeName != null ) {
22+
return javaTypeName;
23+
}
24+
else {
25+
final List<SqmSelectableNode<?>> items =
26+
selectStatement.getQuerySpec().getSelectClause().getSelectionItems();
27+
final SqmExpressible<?> expressible;
28+
if ( items.size() == 1 && (expressible = items.get( 0 ).getExpressible()) != null ) {
29+
final String typeName = expressible.getTypeName();
30+
final TypeElement entityType = context.entityType( typeName );
31+
return entityType == null ? typeName : entityType.getQualifiedName().toString();
32+
}
33+
else {
34+
return "Object[]";
35+
}
36+
}
37+
}
38+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.processor.test.namedentity;
6+
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.Id;
9+
import jakarta.persistence.NamedQuery;
10+
11+
@Entity(name = "Liber")
12+
@NamedQuery(name = "findAllBooks", query = "from Liber")
13+
public class Book {
14+
@Id
15+
private Integer id;
16+
17+
private String name;
18+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.processor.test.namedentity;
6+
7+
import jakarta.persistence.TypedQueryReference;
8+
import org.hibernate.processor.test.util.CompilationTest;
9+
import org.hibernate.processor.test.util.WithClasses;
10+
import org.junit.Test;
11+
12+
import java.lang.reflect.Field;
13+
import java.lang.reflect.ParameterizedType;
14+
import java.lang.reflect.Type;
15+
16+
import static org.hibernate.processor.test.util.TestUtil.assertMetamodelClassGeneratedFor;
17+
import static org.hibernate.processor.test.util.TestUtil.assertPresenceOfFieldInMetamodelFor;
18+
import static org.hibernate.processor.test.util.TestUtil.getFieldFromMetamodelFor;
19+
import static org.hibernate.processor.test.util.TestUtil.getMetaModelSourceAsString;
20+
import static org.junit.Assert.assertEquals;
21+
import static org.junit.Assert.assertTrue;
22+
23+
public class NamedEntityTest extends CompilationTest {
24+
25+
@Test
26+
@WithClasses(Book.class)
27+
public void test() {
28+
System.out.println( getMetaModelSourceAsString( Book.class ) );
29+
30+
assertMetamodelClassGeneratedFor( Book.class );
31+
32+
assertPresenceOfFieldInMetamodelFor( Book.class, "QUERY_FIND_ALL_BOOKS" );
33+
final Field field = getFieldFromMetamodelFor( Book.class, "_findAllBooks_" );
34+
assertEquals( TypedQueryReference.class, field.getType() );
35+
final Type genericType = field.getGenericType();
36+
assertTrue( genericType instanceof ParameterizedType );
37+
final ParameterizedType parameterizedType = (ParameterizedType) genericType;
38+
assertEquals( Book.class, parameterizedType.getActualTypeArguments()[0] );
39+
}
40+
}

0 commit comments

Comments
 (0)