Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hibernate tries to reflectively access metamodel classes not registered for reflection #45503

Closed
zakkak opened this issue Jan 10, 2025 · 5 comments · Fixed by #45506
Closed
Assignees
Labels
area/hibernate-orm Hibernate ORM area/native-image kind/bug Something isn't working
Milestone

Comments

@zakkak
Copy link
Contributor

zakkak commented Jan 10, 2025

Describe the bug

Hibernate seems to be reflectively accessing some metamodel classes that we don't register for reflection in native-mode.

The classes are accessed in https://github.com/hibernate/hibernate-orm/blob/9d52e3c9dfc49a9be804220c2382055d5901daa9/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java#L728-L731

Relates to #41995

Expected behavior

All reflective accesses should be registered.

Actual behavior

Reflective accesses are not registered resulting in warnings like the following when using -H:ThrowMissingRegistrationErrors=:

...
org.graalvm.nativeimage.MissingReflectionRegistrationError: The program tried to reflectively access class

   io.quarkus.it.jpa.db2.Human_

without it being registered for runtime reflection. Add io.quarkus.it.jpa.db2.Human_ to the reflection metadata to solve this problem. See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection for help.
  [email protected]/java.lang.Class.forName(DynamicHub.java:1475)
  io.quarkus.hibernate.orm.runtime.service.FlatClassLoaderService.classForName(FlatClassLoaderService.java:36)
  org.hibernate.metamodel.internal.MetadataContext.populateStaticMetamodel(MetadataContext.java:722)
  org.hibernate.metamodel.internal.MetadataContext.wrapUp(MetadataContext.java:395)
org.graalvm.nativeimage.MissingReflectionRegistrationError: The program tried to reflectively access class

   io.quarkus.it.jpa.db2.Customer_

without it being registered for runtime reflection. Add io.quarkus.it.jpa.db2.Customer_ to the reflection metadata to solve this problem. See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection for help.
  [email protected]/java.lang.Class.forName(DynamicHub.java:1475)
  io.quarkus.hibernate.orm.runtime.service.FlatClassLoaderService.classForName(FlatClassLoaderService.java:36)
  org.hibernate.metamodel.internal.MetadataContext.populateStaticMetamodel(MetadataContext.java:722)
  org.hibernate.metamodel.internal.MetadataContext.wrapUp(MetadataContext.java:345)
org.graalvm.nativeimage.MissingReflectionRegistrationError: The program tried to reflectively access class

   io.quarkus.it.jpa.db2.Person_

without it being registered for runtime reflection. Add io.quarkus.it.jpa.db2.Person_ to the reflection metadata to solve this problem. See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection for help.
  [email protected]/java.lang.Class.forName(DynamicHub.java:1475)
  io.quarkus.hibernate.orm.runtime.service.FlatClassLoaderService.classForName(FlatClassLoaderService.java:36)
  org.hibernate.metamodel.internal.MetadataContext.populateStaticMetamodel(MetadataContext.java:722)
  org.hibernate.metamodel.internal.MetadataContext.wrapUp(MetadataContext.java:345)
...

How to Reproduce?

./mvnw clean package -Dnative -Dnative.surefire.skip \
  -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-23 \
  -pl integration-tests/jpa-db2/ \
  -Dquarkus.native.additional-build-args=-H:ThrowMissingRegistrationErrors=

./integration-tests/jpa-db2/target/quarkus-integration-test-jpa-db2-999-SNAPSHOT-runner -XX:MissingRegistrationReportingMode=Warn

Output of uname -a or ver

No response

Output of java -version

21.0.5

Mandrel or GraalVM version (if different from Java)

Mandrel-24.1.1.0-Final

Quarkus version or git rev

No response

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

No response

@zakkak zakkak added area/native-image kind/bug Something isn't working labels Jan 10, 2025
Copy link

quarkus-bot bot commented Jan 10, 2025

/cc @Karm (native-image), @galderz (native-image), @gsmet (hibernate-orm), @yrodiere (hibernate-orm)

@quarkus-bot quarkus-bot bot added the area/hibernate-orm Hibernate ORM label Jan 10, 2025
@yrodiere
Copy link
Member

yrodiere commented Jan 10, 2025

In some cases (when using the static metamodel -- see #44278) the class will exist, and in this case I agree it should be registered for reflection.

But when the class doesn't exist, this call likely will just ignore the class, so the call was probably harmless until now. With your changes, can/should the (non-existing) classes be registered for reflection?

@yrodiere
Copy link
Member

yrodiere commented Jan 10, 2025

To clarify: in the integration test you mentioned, the metamodel classes (io.quarkus.it.jpa.db2.Human_, io.quarkus.it.jpa.db2.Customer_, ...) do not exist.

@zakkak
Copy link
Contributor Author

zakkak commented Jan 10, 2025

With your changes, can/should the (non-existing) classes be registered for reflection?

Yes, any attempt to access something reflectively (even when it doesn't exist) results in a MissingRegistrationError if it is not registered. The registration should have no impact if the classes don't exist.

@yrodiere
Copy link
Member

Yes, any attempt to access something reflectively (even when it doesn't exist) results in a MissingRegistrationError if it is not registered.

Seems like this could spell trouble for some libraries, but I understand. In our case it should be fine, because...

The registration should have no impact if the classes don't exist.

Great!

In this case, the todo for this issue is to change io.quarkus.hibernate.orm.deployment.JpaJandexScavenger#discoverModelAndRegisterForReflection so that all classes that can have a static metamodel representation (entity/embeddable/mappedsuperclass, I believe?) have that representation registered for reflection. I think it's only needed for the JPA metamodel (Customer_) and not for the Jakarta Data metamodel (_Customer).

Here would be a good place for this change:

reflectiveClass.produce(ReflectiveClassBuildItem.builder(className).methods().fields().build());

I'd do it now, but I'm in the middle of something, and switching branches on the Quarkus repo makes Intellij freeze for 10+ minutes, so it'll wait a bit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/hibernate-orm Hibernate ORM area/native-image kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants