Skip to content

Commit

Permalink
Register arrays of Hibernate ORM's JDBC basic types for reflection
Browse files Browse the repository at this point in the history
Works around https://hibernate.atlassian.net/browse/HHH-16809

(cherry picked from commit 58a4770)
  • Loading branch information
yrodiere authored and gsmet committed Aug 15, 2023
1 parent bb22e8c commit 3f84706
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -461,10 +461,10 @@ public void preGenAnnotationProxies(List<PersistenceUnitDescriptorBuildItem> 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<String> 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]))
Expand Down Expand Up @@ -766,7 +766,7 @@ public void registerInjectServiceMethodsForReflection(CombinedIndexBuildItem ind
Set<String> 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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<DotName> PACKAGE_ANNOTATIONS = List.of(
Expand Down Expand Up @@ -316,4 +316,41 @@ private HibernateOrmAnnotations() {
DotName.createSimple("jakarta.persistence.PreRemove"),
DotName.createSimple("jakarta.persistence.PreUpdate"));

public static final List<DotName> 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"));
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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());
Expand All @@ -53,7 +59,7 @@ public void testNoMissingJpaAnnotation() {
Set<DotName> jpaMappingAnnotations = findRuntimeAnnotations(jpaIndex);
jpaMappingAnnotations.removeIf(name -> name.toString().startsWith("jakarta.persistence.metamodel."));

assertThat(HibernateOrmAnnotations.JPA_MAPPING_ANNOTATIONS)
assertThat(HibernateOrmTypes.JPA_MAPPING_ANNOTATIONS)
.containsExactlyInAnyOrderElementsOf(jpaMappingAnnotations);
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -102,10 +108,33 @@ public void testNoMissingInjectServiceAnnotatedClass() {
Set<DotName> 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<DotName> 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<Type> 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<DotName> findRuntimeAnnotations(Index index) {
Set<DotName> annotations = new HashSet<>();
for (AnnotationInstance retentionAnnotation : index.getAnnotations(RETENTION)) {
Expand Down

0 comments on commit 3f84706

Please sign in to comment.