diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/MetaAttributeGenerationVisitor.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/MetaAttributeGenerationVisitor.java index 37617abdb5fe..873ea6763bd2 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/MetaAttributeGenerationVisitor.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/MetaAttributeGenerationVisitor.java @@ -27,6 +27,7 @@ import java.util.List; import static org.hibernate.processor.util.Constants.ELEMENT_COLLECTION; +import static org.hibernate.processor.util.Constants.LIST_ATTRIBUTE; import static org.hibernate.processor.util.Constants.MANY_TO_ANY; import static org.hibernate.processor.util.Constants.MANY_TO_MANY; import static org.hibernate.processor.util.Constants.MAP_KEY_CLASS; @@ -70,7 +71,13 @@ private Types typeUtils() { @Override public @Nullable AnnotationMetaAttribute visitArray(ArrayType arrayType, Element element) { - return new AnnotationMetaSingleAttribute( entity, element, toArrayTypeString( arrayType, context ) ); + if ( hasAnnotation( element, MANY_TO_MANY, ONE_TO_MANY, ELEMENT_COLLECTION ) ) { + return new AnnotationMetaCollection( entity, element, LIST_ATTRIBUTE, + toTypeString(arrayType.getComponentType()) ); + } + else { + return new AnnotationMetaSingleAttribute( entity, element, toArrayTypeString( arrayType, context ) ); + } } @Override diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/hhh18858/ArrayTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/hhh18858/ArrayTest.java new file mode 100644 index 000000000000..6bf541a0c9db --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/hhh18858/ArrayTest.java @@ -0,0 +1,88 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.hhh18858; + + +import jakarta.persistence.metamodel.ListAttribute; +import jakarta.persistence.metamodel.SingularAttribute; +import org.hibernate.processor.test.util.CompilationTest; +import org.hibernate.processor.test.util.WithClasses; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Collection; + +import static org.hibernate.processor.test.util.TestUtil.getFieldFromMetamodelFor; +import static org.hibernate.processor.test.util.TestUtil.getMetaModelSourceAsString; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Emmanuel Bernard + */ +public class ArrayTest extends CompilationTest { + + @Test + @WithClasses({Competitor.class, Contest.class}) + public void testOneToMany() throws NoSuchFieldException, IllegalAccessException { + System.out.println( getMetaModelSourceAsString( Competitor.class ) ); + assertValidMetamodelField( Competitor.class, "id" ); + assertValidMetamodelField( Competitor.class, "name" ); + + System.out.println( getMetaModelSourceAsString( Contest.class ) ); + assertValidMetamodelField( Contest.class, "id" ); + assertValidMetamodelField( Contest.class, "results" ); + assertValidMetamodelField( Contest.class, "heldIn" ); + } + + private void assertValidMetamodelField(Class entityClass, String fieldName) + throws NoSuchFieldException, IllegalAccessException { + final Field entityField = entityClass.getDeclaredField( fieldName ); + final Class entityFieldType = entityField.getType(); + + final Field modelField = getFieldFromMetamodelFor( entityClass, fieldName ); + final Type modelFieldGenericType = modelField.getGenericType(); + if ( modelFieldGenericType instanceof ParameterizedType parametrized ) { + final Type[] typeArguments = parametrized.getActualTypeArguments(); + assertEquals( 2, typeArguments.length ); + assertEquals( entityClass, typeArguments[0] ); + if ( Collection.class.isAssignableFrom( entityFieldType ) || entityFieldType.isArray() ) { + assertEquals( ListAttribute.class, parametrized.getRawType() ); + if ( Collection.class.isAssignableFrom( entityFieldType ) ) { + final ParameterizedType entityFieldGenericType = (ParameterizedType) entityField.getGenericType(); + assertEquals( entityFieldGenericType.getActualTypeArguments()[0], typeArguments[1] ); + } + else if ( entityFieldType.getComponentType().isPrimitive() ) { + assertEquals( + entityFieldType.getComponentType(), + ((Class) typeArguments[1]).getDeclaredField( "TYPE" ).get( null ) + ); + } + else { + assertEquals( entityFieldType.getComponentType(), typeArguments[1] ); + } + } + else { + assertEquals( SingularAttribute.class, parametrized.getRawType() ); + if ( entityFieldType.isPrimitive() ) { + assertEquals( + entityFieldType, + ((Class) typeArguments[1]).getDeclaredField( "TYPE" ).get( null ) + ); + } + else { + assertEquals( entityFieldType, typeArguments[1] ); + } + } + } + else { + Assertions.fail(); + } + + } + +} diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/hhh18858/Competitor.java b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/hhh18858/Competitor.java new file mode 100644 index 000000000000..11d3ba54dacb --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/hhh18858/Competitor.java @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.hhh18858; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +/** + * @author Emmanuel Bernard + */ +@Entity +public class Competitor { + private int id; + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Id + @GeneratedValue + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } +} diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/hhh18858/Contest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/hhh18858/Contest.java new file mode 100644 index 000000000000..5e0cb31c8424 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/hhh18858/Contest.java @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.hhh18858; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OrderColumn; + +import org.hibernate.annotations.ListIndexBase; + +/** + * @author Emmanuel Bernard + */ +@Entity +public class Contest { + private int id; + private Competitor[] results; + private int[] heldIn; + + @Id + @GeneratedValue + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + @OneToMany(cascade = CascadeType.ALL) + @OrderColumn(name = "pos") + public Competitor[] getResults() { + return results; + } + + public void setResults(Competitor[] results) { + this.results = results; + } + + @ElementCollection + @OrderColumn + @ListIndexBase( 1 ) + public int[] getHeldIn() { + return heldIn; + } + + public void setHeldIn(int[] heldIn) { + this.heldIn = heldIn; + } + + /*public enum Month { + January, February, March, April, May, June, July, August, September, October, November, December; + };*/ +}