diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/multivaluebinding/Post.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/multivaluebinding/Post.java new file mode 100644 index 000000000000..d3f3e5a3c397 --- /dev/null +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/multivaluebinding/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.data.multivaluebinding; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQuery; + +@Entity +@NamedQuery(name = "#getPostsByName", query = "from Post p where p.name in (:names)") +public class Post { + @Id + Integer id; + + String name; + + Integer value; +} diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/multivaluebinding/PostRepository.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/multivaluebinding/PostRepository.java new file mode 100644 index 000000000000..4125356a5a24 --- /dev/null +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/multivaluebinding/PostRepository.java @@ -0,0 +1,19 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.data.multivaluebinding; + +import jakarta.data.repository.DataRepository; +import jakarta.data.repository.Query; +import jakarta.data.repository.Repository; + +import java.util.Collection; +import java.util.List; + +@Repository +public interface PostRepository extends DataRepository { + + @Query("from Post p where p.name in (:names)") + List getPostsByName(Collection names); +} diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/multivaluebinding/TopicPostTest.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/multivaluebinding/TopicPostTest.java new file mode 100644 index 000000000000..bc06bf3d6444 --- /dev/null +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/multivaluebinding/TopicPostTest.java @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.data.multivaluebinding; + +import jakarta.persistence.EntityManager; +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.lang.reflect.Type; +import java.util.Collection; +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; +import static org.junit.jupiter.api.Assertions.fail; + +public class TopicPostTest extends CompilationTest { + @Test + @WithClasses({Post.class, PostRepository.class}) + public void test() { + assertMetamodelClassGeneratedFor( Post.class, true ); + assertMetamodelClassGeneratedFor( Post.class ); + assertMetamodelClassGeneratedFor( PostRepository.class ); + + assertPresenceOfMethodInMetamodelFor( Post.class, "getPostsByName", EntityManager.class, List.class ); + final Method method = getMethodFromMetamodelFor( Post.class, "getPostsByName", EntityManager.class, List.class ); + final Type methodParam = method.getGenericParameterTypes()[1]; + if ( methodParam instanceof ParameterizedType parameterized ) { + assertEquals( String.class, parameterized.getActualTypeArguments()[0] ); + } + else { + fail(); + } + + assertPresenceOfMethodInMetamodelFor( PostRepository.class, "getPostsByName", Collection.class ); + final Method repositoryMethod = getMethodFromMetamodelFor( PostRepository.class, "getPostsByName", Collection.class ); + final Type repositoryMethodParam = repositoryMethod.getGenericParameterTypes()[0]; + if ( repositoryMethodParam instanceof ParameterizedType parameterized ) { + assertEquals( String.class, parameterized.getActualTypeArguments()[0] ); + } + else { + fail(); + } + } +} diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java index 162d6de043b1..e2fa85d1b3e3 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java @@ -64,6 +64,7 @@ import static java.beans.Introspector.decapitalize; import static java.lang.Boolean.FALSE; import static java.util.Collections.emptyList; +import static java.util.Objects.requireNonNullElse; import static java.util.stream.Collectors.toList; import static javax.lang.model.util.ElementFilter.fieldsIn; import static javax.lang.model.util.ElementFilter.methodsIn; @@ -2738,11 +2739,13 @@ private void checkParameter( if ( queryParamType!=null //TODO: arguments of functions get assigned "unknown" which sucks && !"unknown".equals(queryParamType) ) { + final String realQueryParamType = + requireNonNullElse( context.qualifiedNameForEntityName( queryParamType ), queryParamType ); if ( param.getName() != null ) { - checkNamedParameter(param, paramNames, paramTypes, method, mirror, value, queryParamType); + checkNamedParameter(param, paramNames, paramTypes, method, mirror, value, realQueryParamType); } else if ( param.getPosition() != null ) { - checkOrdinalParameter(param, paramNames, paramTypes, method, mirror, value, queryParamType); + checkOrdinalParameter(param, paramNames, paramTypes, method, mirror, value, realQueryParamType); } } } 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..d4f49592f2a3 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 @@ -148,10 +148,20 @@ private void parameters(TreeSet> sortedParameters, StringBuilder declaration .append(", "); } - declaration - .append(parameterType(param)) - .append(" ") - .append(parameterName(param)); + if ( param.allowMultiValuedBinding() ) { + declaration + .append(annotationMeta.importType(Constants.LIST)) + .append('<') + .append( parameterType( param ) ) + .append("> ") + .append( parameterName( param ) ); + } + else { + declaration + .append( parameterType( param ) ) + .append( " " ) + .append( parameterName( param ) ); + } } declaration .append(')');