diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMeta.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMeta.java index 06db3329d229..e16f91bf2751 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMeta.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMeta.java @@ -110,8 +110,11 @@ private void handleNamedQuery(AnnotationMirror mirror, boolean checkHql) { if ( !isJakartaDataStyle() && statement instanceof SqmSelectStatement selectStatement ) { if ( isQueryMethodName( name ) ) { + final AnnotationValue annotationValue = getAnnotationValue( mirror, "resultClass" ); + final String resultType = annotationValue != null + ? annotationValue.getValue().toString() + : resultType( selectStatement, context ); putMember( name, - // TODO: respect @NamedQuery(resultClass) new NamedQueryMethod( this, selectStatement, @@ -119,7 +122,8 @@ private void handleNamedQuery(AnnotationMirror mirror, boolean checkHql) { isRepository(), getSessionType(), getSessionVariableName(), - context.addNonnullAnnotation() + context.addNonnullAnnotation(), + resultType ) ); } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/NamedQueryMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/NamedQueryMethod.java index 5f8a8fc9eff7..de8274ce09e4 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/NamedQueryMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/NamedQueryMethod.java @@ -15,7 +15,6 @@ import java.util.TreeSet; import static org.hibernate.processor.util.StringUtil.nameToFieldName; -import static org.hibernate.processor.util.SqmTypeUtils.resultType; /** * @author Gavin King @@ -28,6 +27,7 @@ class NamedQueryMethod implements MetaAttribute { private final boolean reactive; private final String sessionVariableName; private final boolean addNonnullAnnotation; + private final String resultClass; public NamedQueryMethod( AnnotationMeta annotationMeta, @@ -36,7 +36,8 @@ public NamedQueryMethod( boolean belongsToRepository, @Nullable String sessionType, String sessionVariableName, - boolean addNonnullAnnotation) { + boolean addNonnullAnnotation, + String resultClass) { this.annotationMeta = annotationMeta; this.select = select; this.name = name; @@ -44,6 +45,7 @@ public NamedQueryMethod( this.reactive = Constants.MUTINY_SESSION.equals(sessionType); this.sessionVariableName = sessionVariableName; this.addNonnullAnnotation = addNonnullAnnotation; + this.resultClass = resultClass; } @Override @@ -72,7 +74,7 @@ public String getAttributeDeclarationString() { .append(".createNamedQuery(") .append(fieldName()) .append(", ") - .append( annotationMeta.importType( resultType( select, annotationMeta.getContext() ) ) ) + .append( annotationMeta.importType( resultClass ) ) .append( ".class)"); for ( SqmParameter param : sortedParameters ) { declaration @@ -123,7 +125,7 @@ private void returnType(StringBuilder declaration) { declaration .append(annotationMeta.importType(Constants.LIST)) .append('<') - .append( annotationMeta.importType( resultType( select, annotationMeta.getContext() ) ) ) + .append( annotationMeta.importType( resultClass ) ) .append("> ") .append(name); if ( reactive ) { diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/resultclass/NameValue.java b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/resultclass/NameValue.java new file mode 100644 index 000000000000..bd0e6b060b4f --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/resultclass/NameValue.java @@ -0,0 +1,9 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.resultclass; + +public record NameValue(String name, Integer value) { + +} diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/resultclass/Post.java b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/resultclass/Post.java new file mode 100644 index 000000000000..38c9948f62f6 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/resultclass/Post.java @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.resultclass; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQuery; + +@Entity +@NamedQuery(name = "#getNameValue", query = "select p.name, p.value from Post p", resultClass = NameValue.class) +public class Post { + @Id + Integer id; + + String name; + + Integer value; +} diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/resultclass/ResultClassTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/resultclass/ResultClassTest.java new file mode 100644 index 000000000000..3306cb41dc3c --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/resultclass/ResultClassTest.java @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.resultclass; + +import jakarta.persistence.EntityManager; +import org.assertj.core.api.Assertions; +import org.hibernate.processor.test.util.CompilationTest; +import org.hibernate.processor.test.util.WithClasses; +import org.junit.Test; + +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.util.List; + +import static org.hibernate.processor.test.util.TestUtil.assertMetamodelClassGeneratedFor; +import static org.hibernate.processor.test.util.TestUtil.assertPresenceOfMethodInMetamodelFor; +import static org.hibernate.processor.test.util.TestUtil.getMetaModelSourceAsString; +import static org.hibernate.processor.test.util.TestUtil.getMethodFromMetamodelFor; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ResultClassTest extends CompilationTest { + @Test + @WithClasses({Post.class, NameValue.class}) + public void test() { + System.out.println( getMetaModelSourceAsString( Post.class ) ); + assertMetamodelClassGeneratedFor( Post.class ); + + assertPresenceOfMethodInMetamodelFor( Post.class, "getNameValue", EntityManager.class ); + final Method method = getMethodFromMetamodelFor( Post.class, "getNameValue", EntityManager.class ); + if ( method.getGenericReturnType() instanceof ParameterizedType parameterized ) { + assertEquals( List.class, parameterized.getRawType() ); + assertEquals( NameValue.class, parameterized.getActualTypeArguments()[0] ); + } + else { + Assertions.fail(); + } + } +}