Affects: 6.0.11

I get the com.oracle.svm.core.jdk.UnsupportedFeatureError when using a simple repository.

@Repository
public interface VoucherRepository extends CrudRepository<Voucher, Integer> {
    List<Voucher> findByMsisdn(String msisdn);
}

The only workaround I've found so far is to run the native-image command with an agent, then rebuild my image

$JAVA_HOME/bin/java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image -jar target/graalvm-springdata-jpa-issue-0.0.1-SNAPSHOT.jar

I have a git hub project to reproduce the issue on https://github.com/mawabokasper/graalvm-springdata-jpa-issue , it's

Stacktrace

15-08-2023 07:28:00.022 [batch-file-1] ERROR o.s.a.i.SimpleAsyncUncaughtExceptionHandler.handleUncaughtException - Unexpected exception occurred invoking async method: public void com.vouchermanagement.thissales.batch.sales.event.SalesBatchFileEventListener.processFile(com.vouchermanagement.thissales.batch.sales.event.SalesBatchFileEvent)
com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [interface org.hibernate.query.hql.spi.SqmQueryImplementor, interface org.hibernate.query.sqm.internal.SqmInterpretationsKey$InterpretationsKeySource, interface org.hibernate.query.spi.DomainQueryExecutionContext, interface org.hibernate.query.SelectionQuery, interface org.hibernate.query.CommonQueryContract] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles=<comma-separated-config-files> and -H:DynamicProxyConfigurationResources=<comma-separated-config-resources> options.
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:92)
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.reflect.proxy.DynamicProxySupport.getProxyClass(DynamicProxySupport.java:171)
        at java.base@20.0.2/java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:47)
        at java.base@20.0.2/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1034)
        at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:316)
        at jdk.proxy4/jdk.proxy4.$Proxy70.createQuery(Unknown Source)
        at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.createQuery(PartTreeJpaQuery.java:297)
        at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.createQuery(PartTreeJpaQuery.java:242)
        at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.doCreateQuery(PartTreeJpaQuery.java:113)
        at org.springframework.data.jpa.repository.query.AbstractJpaQuery.createQuery(AbstractJpaQuery.java:234)
        at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:223)
        at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:92)
        at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:148)
        at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:136)
        at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:136)
        at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120)
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:164)
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:72)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:391)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:244)
        at jdk.proxy4/jdk.proxy4.$Proxy59.findTop1ByMeterNumberAndStatusIsOrderByDateCreatedAsc(Unknown Source)
        at com.vouchermanagement.thissales.batch.sales.AbstractSalesFileHandler.lambda$processLines$0(AbstractSalesFileHandler.java:74)
        at java.base@20.0.2/java.util.ArrayList.forEach(ArrayList.java:1511)
        at com.vouchermanagement.thissales.batch.sales.AbstractSalesFileHandler.processLines(AbstractSalesFileHandler.java:49)
        at com.vouchermanagement.thissales.batch.sales.AbstractSalesFileHandler.process(AbstractSalesFileHandler.java:40)
        at com.vouchermanagement.thissales.batch.sales.event.SalesBatchFileEventListener.processFile(SalesBatchFileEventListener.java:29)
        at java.base@20.0.2/java.lang.reflect.Method.invoke(Method.java:578)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:756)
        at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115)
        at java.base@20.0.2/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base@20.0.2/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base@20.0.2/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base@20.0.2/java.lang.Thread.runWith(Thread.java:1636)
        at java.base@20.0.2/java.lang.Thread.run(Thread.java:1623)
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:807)
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:210)

Comment From: sdeleuze

A bit surprised that such sample project fails, but I can indeed reproduce with the project provided.

Adding a META-INF/native-image/proxy-config.json resource file (or the equivalent hint with RuntimeHintsRegistrar) with the following content fixes the issue:

[
  {
    "interfaces":[
      "org.hibernate.query.hql.spi.SqmQueryImplementor",
      "org.hibernate.query.sqm.internal.SqmInterpretationsKey$InterpretationsKeySource",
      "org.hibernate.query.spi.DomainQueryExecutionContext",
      "org.hibernate.query.SelectionQuery",
      "org.hibernate.query.CommonQueryContract"
    ]
  }
]

Since we have only Hibernate interfaces here, it should be provided on https://github.com/oracle/graalvm-reachability-metadata side. @mawabokasper Could you please create an issue (with your existing repro) on the reachability metadata repository?

Comment From: mawabokasper

Thanx Sébastien

The fix works for me too, appreciate the feedback.

I've opened an issue on the graalvm-reachability-metadata side, https://github.com/oracle/graalvm-reachability-metadata/issues/368

Regards

Comment From: sdeleuze

After a second look, those proxies are created on Spring side by SharedEntityManagerCreator and should be handled on Spring side, so I reopen this issue.

One tricky point is that we get that error because Hibernate reachability metadata for 6.2.0.Final do not contain a proxy-config.json file (here on purpose) while 6.1.1.Final does, hence why this was previous hidden.