diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/GraalVMFeatures.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/GraalVMFeatures.java index d0d2e124b8f80..b4f4ae6caa1bf 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/GraalVMFeatures.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/GraalVMFeatures.java @@ -28,4 +28,13 @@ ReflectiveClassBuildItem registerGeneratorClassesForReflections() { .build(); } + // Workaround for https://hibernate.atlassian.net/browse/HHH-16809 + // See https://github.com/hibernate/hibernate-orm/pull/6815#issuecomment-1662197545 + @BuildStep + ReflectiveClassBuildItem registerJdbcArrayTypesForReflection() { + return ReflectiveClassBuildItem + .builder(HibernateOrmTypes.JDBC_JAVA_TYPES.stream().map(d -> d.toString() + "[]").toArray(String[]::new)) + .build(); + } + } diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java index ed82729ff903b..a2117baab9210 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java @@ -461,10 +461,10 @@ public void preGenAnnotationProxies(List per // but there are plans to make deep changes to XML mapping in ORM (to rely on Jandex directly), // so let's not waste our time on optimizations that won't be relevant in a few months. List annotationClassNames = new ArrayList<>(); - for (DotName name : HibernateOrmAnnotations.JPA_MAPPING_ANNOTATIONS) { + for (DotName name : HibernateOrmTypes.JPA_MAPPING_ANNOTATIONS) { annotationClassNames.add(name.toString()); } - for (DotName name : HibernateOrmAnnotations.HIBERNATE_MAPPING_ANNOTATIONS) { + for (DotName name : HibernateOrmTypes.HIBERNATE_MAPPING_ANNOTATIONS) { annotationClassNames.add(name.toString()); } reflective.produce(ReflectiveClassBuildItem.builder(annotationClassNames.toArray(new String[0])) @@ -766,7 +766,7 @@ public void registerInjectServiceMethodsForReflection(CombinedIndexBuildItem ind Set classes = new HashSet<>(); // Built-in service classes; can't rely on Jandex as Hibernate ORM is not indexed by default. - HibernateOrmAnnotations.ANNOTATED_WITH_INJECT_SERVICE.stream() + HibernateOrmTypes.ANNOTATED_WITH_INJECT_SERVICE.stream() .map(DotName::toString) .forEach(classes::add); diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmAnnotations.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmTypes.java similarity index 91% rename from extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmAnnotations.java rename to extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmTypes.java index 384b8239753c3..3b8a7f8e9e0ab 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmAnnotations.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmTypes.java @@ -4,9 +4,9 @@ import org.jboss.jandex.DotName; -public final class HibernateOrmAnnotations { +public final class HibernateOrmTypes { - private HibernateOrmAnnotations() { + private HibernateOrmTypes() { } public static final List PACKAGE_ANNOTATIONS = List.of( @@ -316,4 +316,41 @@ private HibernateOrmAnnotations() { DotName.createSimple("jakarta.persistence.PreRemove"), DotName.createSimple("jakarta.persistence.PreUpdate")); + public static final List JDBC_JAVA_TYPES = List.of( + DotName.createSimple("java.lang.Boolean"), + DotName.createSimple("java.lang.Byte"), + DotName.createSimple("java.lang.Character"), + DotName.createSimple("java.lang.Class"), + DotName.createSimple("java.lang.Double"), + DotName.createSimple("java.lang.Float"), + DotName.createSimple("java.lang.Integer"), + DotName.createSimple("java.lang.Long"), + DotName.createSimple("java.lang.Object"), + DotName.createSimple("java.lang.Short"), + DotName.createSimple("java.lang.String"), + DotName.createSimple("java.math.BigDecimal"), + DotName.createSimple("java.math.BigInteger"), + DotName.createSimple("java.net.InetAddress"), + DotName.createSimple("java.net.URL"), + DotName.createSimple("java.sql.Blob"), + DotName.createSimple("java.sql.Clob"), + DotName.createSimple("java.sql.NClob"), + DotName.createSimple("java.time.Duration"), + DotName.createSimple("java.time.Instant"), + DotName.createSimple("java.time.LocalDate"), + DotName.createSimple("java.time.LocalDateTime"), + DotName.createSimple("java.time.LocalTime"), + DotName.createSimple("java.time.OffsetDateTime"), + DotName.createSimple("java.time.OffsetTime"), + DotName.createSimple("java.time.Year"), + DotName.createSimple("java.time.ZoneId"), + DotName.createSimple("java.time.ZoneOffset"), + DotName.createSimple("java.time.ZonedDateTime"), + DotName.createSimple("java.util.Calendar"), + DotName.createSimple("java.util.Currency"), + DotName.createSimple("java.util.Date"), + DotName.createSimple("java.util.Locale"), + DotName.createSimple("java.util.Map$Entry"), + DotName.createSimple("java.util.TimeZone"), + DotName.createSimple("java.util.UUID")); } diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/JpaJandexScavenger.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/JpaJandexScavenger.java index 729da9756567e..84edc7d837e66 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/JpaJandexScavenger.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/JpaJandexScavenger.java @@ -85,7 +85,7 @@ public final class JpaJandexScavenger { public JpaModelBuildItem discoverModelAndRegisterForReflection() { Collector collector = new Collector(); - for (DotName packageAnnotation : HibernateOrmAnnotations.PACKAGE_ANNOTATIONS) { + for (DotName packageAnnotation : HibernateOrmTypes.PACKAGE_ANNOTATIONS) { enlistJPAModelAnnotatedPackages(collector, packageAnnotation); } enlistJPAModelClasses(collector, ClassNames.JPA_ENTITY); @@ -95,7 +95,7 @@ public JpaModelBuildItem discoverModelAndRegisterForReflection() { enlistEmbeddedsAndElementCollections(collector); enlistPotentialCdiBeanClasses(collector, ClassNames.CONVERTER); - for (DotName annotation : HibernateOrmAnnotations.JPA_LISTENER_ANNOTATIONS) { + for (DotName annotation : HibernateOrmTypes.JPA_LISTENER_ANNOTATIONS) { enlistPotentialCdiBeanClasses(collector, annotation); } diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateOrmAnnotationsTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateOrmTypesTest.java similarity index 78% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateOrmAnnotationsTest.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateOrmTypesTest.java index 397b417c66da6..992cb3d7b33a2 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateOrmAnnotationsTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/HibernateOrmTypesTest.java @@ -8,6 +8,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.lang.reflect.Modifier; import java.net.URL; import java.util.Arrays; import java.util.HashSet; @@ -24,17 +25,22 @@ import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; import org.jboss.jandex.Index; +import org.jboss.jandex.IndexView; +import org.jboss.jandex.Type; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import io.quarkus.deployment.index.IndexWrapper; import io.quarkus.deployment.index.IndexingUtil; +import io.quarkus.deployment.index.PersistentClassIndex; +import io.quarkus.deployment.util.JandexUtil; import io.quarkus.hibernate.orm.deployment.ClassNames; -import io.quarkus.hibernate.orm.deployment.HibernateOrmAnnotations; +import io.quarkus.hibernate.orm.deployment.HibernateOrmTypes; /** - * Test that hardcoded lists of Hibernate ORM annotations stay up-to-date. + * Test that hardcoded lists of Hibernate ORM types stay up-to-date. */ -public class HibernateOrmAnnotationsTest { +public class HibernateOrmTypesTest { private static final DotName RETENTION = DotName.createSimple(Retention.class.getName()); private static final DotName TARGET = DotName.createSimple(Target.class.getName()); @@ -53,7 +59,7 @@ public void testNoMissingJpaAnnotation() { Set jpaMappingAnnotations = findRuntimeAnnotations(jpaIndex); jpaMappingAnnotations.removeIf(name -> name.toString().startsWith("jakarta.persistence.metamodel.")); - assertThat(HibernateOrmAnnotations.JPA_MAPPING_ANNOTATIONS) + assertThat(HibernateOrmTypes.JPA_MAPPING_ANNOTATIONS) .containsExactlyInAnyOrderElementsOf(jpaMappingAnnotations); } @@ -65,7 +71,7 @@ public void testNoMissingJpaListenerAnnotation() { .filter(name -> listenerAnnotationNamePattern.matcher(name.toString()).matches()) .collect(Collectors.toSet()); - assertThat(HibernateOrmAnnotations.JPA_LISTENER_ANNOTATIONS) + assertThat(HibernateOrmTypes.JPA_LISTENER_ANNOTATIONS) .containsExactlyInAnyOrderElementsOf(jpaMappingAnnotations); } @@ -76,7 +82,7 @@ public void testNoMissingHibernateAnnotation() { hibernateMappingAnnotations.removeIf(name -> name.toString().contains(".spi.")); ignoreInternalAnnotations(hibernateMappingAnnotations); - assertThat(HibernateOrmAnnotations.HIBERNATE_MAPPING_ANNOTATIONS) + assertThat(HibernateOrmTypes.HIBERNATE_MAPPING_ANNOTATIONS) .containsExactlyInAnyOrderElementsOf(hibernateMappingAnnotations); } @@ -93,7 +99,7 @@ public void testNoMissingPackageLevelAnnotation() { packageLevelHibernateAnnotations.removeIf(name -> name.toString().contains(".internal.")); ignoreInternalAnnotations(packageLevelHibernateAnnotations); - assertThat(HibernateOrmAnnotations.PACKAGE_ANNOTATIONS) + assertThat(HibernateOrmTypes.PACKAGE_ANNOTATIONS) .containsExactlyInAnyOrderElementsOf(packageLevelHibernateAnnotations); } @@ -102,10 +108,33 @@ public void testNoMissingInjectServiceAnnotatedClass() { Set injectServiceAnnotatedClasses = findClassesWithMethodsAnnotatedWith(hibernateIndex, ClassNames.INJECT_SERVICE); - assertThat(HibernateOrmAnnotations.ANNOTATED_WITH_INJECT_SERVICE) + assertThat(HibernateOrmTypes.ANNOTATED_WITH_INJECT_SERVICE) .containsExactlyInAnyOrderElementsOf(injectServiceAnnotatedClasses); } + @Test + public void testNoMissingJdbcJavaTypeClass() { + Set jdbcJavaTypeNames = new TreeSet<>(); + DotName basicJavaTypeName = DotName.createSimple("org.hibernate.type.descriptor.java.BasicJavaType"); + IndexView hibernateAndJdkIndex = new IndexWrapper(hibernateIndex, Thread.currentThread().getContextClassLoader(), + new PersistentClassIndex()); + + for (ClassInfo basicJavaTypeImplInfo : hibernateIndex.getAllKnownImplementors(basicJavaTypeName)) { + if (Modifier.isAbstract(basicJavaTypeImplInfo.flags())) { + continue; + } + List typeParams = JandexUtil.resolveTypeParameters(basicJavaTypeImplInfo.name(), basicJavaTypeName, + hibernateAndJdkIndex); + Type jdbcJavaType = typeParams.get(0); + if (jdbcJavaType.kind() == Type.Kind.CLASS) { + jdbcJavaTypeNames.add(jdbcJavaType.name()); + } + } + + assertThat(HibernateOrmTypes.JDBC_JAVA_TYPES) + .containsExactlyInAnyOrderElementsOf(jdbcJavaTypeNames); + } + private Set findRuntimeAnnotations(Index index) { Set annotations = new HashSet<>(); for (AnnotationInstance retentionAnnotation : index.getAnnotations(RETENTION)) {