How to correctly disable Byte Buddy for GraalVM Native Image

Following the discussion I still can’t find a way on how to disable Byte Buddy, as I use GraalVM Native Image (stricly speaking, I deploy it on AWS Lambda as an Custom Runtime).

I use Hibernate 7.2.4.Final (no Spring or Spring Boot). This is my sample project.

I use hibernate-enhance-maven-plugin

       <groupId>org.hibernate.orm.tooling</groupId>
            <artifactId>hibernate-enhance-maven-plugin</artifactId>
            <version>6.6.42.Final</version>
            <executions>
                <execution>
                    <id>enhance</id>
                    <goals>
                        <goal>enhance</goal>
                    </goals>
                    <configuration>
                        <enableLazyInitialization>true</enableLazyInitialization>
                        <enableDirtyTracking>true</enableDirtyTracking>
                        <enableAssociationManagement>true</enableAssociationManagement>
                    </configuration>
                </execution>
            </executions>
        </plugin>

And the flag Environment.BYTECODE_PROVIDER=“none” doesn’t have impact anymore. If I run my application, dynamic class loading with Byte Buddy kicks in which leads to exceptions like:

Caused by: com.oracle.svm.core.jdk.UnsupportedFeatureError: Classes cannot be defined at runtime by default when using ahead-of-time Native Image compilation. Tried to define class ‘net.bytebuddy.utility.Invoker$Dispatcher’.

How I can disable it and use no op byte code provider for the GraalVM Native Image?

Thanks a lot!

Hello @Vadym_Kazulkin, you can override the default bytecode provider by specifying the implementation of org.hibernate.bytecode.spi.BytecodeProvider you wish to use through the Java Service loader contract.

Hibernate provides a default no-op implementation: org.hibernate.bytecode.internal.none.BytecodeProviderImpl.

Hi @mbladel

Thanks, I did that by providing META-INF/services/org.hibernate.bytecode.spi.BytecodeProvider with org.hibernate.bytecode.internal.none.BytecodeProviderImpl and included this file into the native image . I see that the only implementation will be loaded when executing

ServiceLoader<org.hibernate.bytecode.spi.BytecodeProvider> loader =ServiceLoader.load(org.hibernate.bytecode.spi.BytecodeProvider.class);

is the no-op one org.hibernate.bytecode.internal.none.BytecodeProviderImpl

But the actuall code to load the service in the Hibernate class org.hibernate.boot.registry.classloading.internal.AggregatedServiceLoader.$ClassPathAndModulePathAggregatedServiceLoader is much more complex and involves the search for the available implementation in the module system (which seems not to be there), class path and service loader and still loads the Byte Buddy implementation which crashes in the GraalVM Native Image. So very curious how to include only org.hibernate.bytecode.internal.none.BytecodeProviderImpl impementation

Here is whole error stack trace:

2026-02-18T15:58:06.166Z

Exception in thread "main" java.util.ServiceConfigurationError: org.hibernate.bytecode.spi.BytecodeProvider: Provider org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl could not be instantiated

2026-02-18T15:58:06.166Z

at java.base@25.0.2/java.util.ServiceLoader.fail(ServiceLoader.java:552)

2026-02-18T15:58:06.166Z

at java.base@25.0.2/java.util.ServiceLoader$ProviderImpl.newInstance(ServiceLoader.java:712)

2026-02-18T15:58:06.166Z

at java.base@25.0.2/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:672)

2026-02-18T15:58:06.166Z

at org.hibernate.boot.registry.classloading.internal.AggregatedServiceLoader$ClassPathAndModulePathAggregatedServiceLoader.collectServiceIfNotDuplicate(AggregatedServiceLoader.java:177)

2026-02-18T15:58:06.166Z

at org.hibernate.boot.registry.classloading.internal.AggregatedServiceLoader$ClassPathAndModulePathAggregatedServiceLoader.loadAll(AggregatedServiceLoader.java:119)

2026-02-18T15:58:06.166Z

at org.hibernate.boot.registry.classloading.internal.AggregatedServiceLoader$ClassPathAndModulePathAggregatedServiceLoader.getAll(AggregatedServiceLoader.java:106)

2026-02-18T15:58:06.166Z

at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.loadJavaServices(ClassLoaderServiceImpl.java:203)

2026-02-18T15:58:06.166Z

at org.hibernate.bytecode.internal.BytecodeProviderInitiator.initiateService(BytecodeProviderInitiator.java:33)

2026-02-18T15:58:06.166Z

at org.hibernate.bytecode.internal.BytecodeProviderInitiator.initiateService(BytecodeProviderInitiator.java:16)

2026-02-18T15:58:06.166Z

at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:133)

2026-02-18T15:58:06.166Z

at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:260)

2026-02-18T15:58:06.166Z

at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:235)

2026-02-18T15:58:06.166Z

at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:212)

2026-02-18T15:58:06.166Z

at org.hibernate.boot.internal.SessionFactoryBuilderImpl.<init>(SessionFactoryBuilderImpl.java:69)

2026-02-18T15:58:06.166Z

at org.hibernate.boot.internal.SessionFactoryBuilderImpl.<init>(SessionFactoryBuilderImpl.java:46)

2026-02-18T15:58:06.166Z

at org.hibernate.boot.internal.DefaultSessionFactoryBuilderService.createSessionFactoryBuilder(DefaultSessionFactoryBuilderService.java:24)

2026-02-18T15:58:06.166Z

at org.hibernate.boot.internal.MetadataImpl.getFactoryBuilder(MetadataImpl.java:191)

2026-02-18T15:58:06.166Z

at org.hibernate.boot.internal.MetadataImpl.getSessionFactoryBuilder(MetadataImpl.java:159)

2026-02-18T15:58:06.166Z

at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1081)
2026-02-18T15:58:06.166Z
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1134)
2026-02-18T15:58:06.166Z
at software.amazonaws.example.product.dao.HibernateUtils.getHibernateSessionFactory(HibernateUtils.java:44)
2026-02-18T15:58:06.166Z
at software.amazonaws.example.product.dao.HibernateUtils.<clinit>(HibernateUtils.java:25)
2026-02-18T15:58:06.166Z
at software.amazonaws.example.product.dao.ProductDao.<clinit>(ProductDao.java:11)
2026-02-18T15:58:06.166Z
at software.amazonaws.example.product.handler.CreateProductHandler.<clinit>(CreateProductHandler.java:18)

2026-02-18T15:58:06.166Z

at java.base@25.0.2/java.lang.Class.ensureInitialized(DynamicHub.java:778)

2026-02-18T15:58:06.166Z

at java.base@25.0.2/java.lang.Class.forName(DynamicHub.java:1717)

2026-02-18T15:58:06.166Z

at java.base@25.0.2/java.lang.Class.forName(DynamicHub.java:1654)

@Vadym_Kazulkin it really depends how your class-path looks like, but I guess that we could be loading the existing default service provider defined in Hibernate’s own META-INF/services. As was discussed in the PR related to the Jira you originally posted, during native compilation this “default” would need to be overridden and the none provider be left as the only service provider.

PS: if you want native compilation support while still taking advantage of all of Hibernate’s bytecode enhancement optimizations + retain laziness thanks to proxy support, Quarkus will do that for you :slight_smile:

@mbladel @beikov

I now debugged a bit. Even if I provide my own implementation of the Bytecode Provider in META-INF/service of my application, both the hibernate-core own and my implementations will be loaded due to the complex rules in the org.hibernate.boot.registry.classloading.internal.AggregatedServiceLoader.$ClassPathAndModulePathAggregatedServiceLoader class. And then Byte Buddy crashes the native image. I patched the hibernate-core.jar and replaced the implementation with no op Bytecode Provider manually, and then it worked. Then I added ByteBuddy implementation in the META-INF/services of my own app and then again both Bytecode Providers have been loaded. So I think it’s a bug (it shouldn’t load the Byte Buddy if I override it and it should load only one implementation as otherwise how I can override/disable the default one?). So, please provide a clean way of how I can override the default implementation with no op Bytecode Provider.

I also experimented with GraalVM exclude resourced policies to exclude the default implementation (by simply not including the hibernate-core META-INF/services/org.hibernate.bytecode.spi.BytecodeProvider into the native image), but didn’t have success until now as this file is always there, loads ByteBuddy and crashes in the native image.

Yes, I know that Quarkus, Spring Boot and can do this kind of magic and exchange the provider implementation and the compile time, but I’d like to know how to override it without those frameworks.

By the way, by manually patching described above, I now already have a working application based on Native Image and deployable on AWS Lambda as Custom Runtime. That was a lot of work (see the native image config files and pom.xml) and I’d like to do the last step by correctly overriding org.hibernate.bytecode.internal.none.BytecodeProviderImpl and getting rid of this patching.

I could “fix” the above described issue with multiple Bytecode Providers on my own. I first build the uber-jar with maven-shade-plugin and then use this jar (instead of class path) to create the GraalVM Native Image. With that, I saw that it of course flattens META-INF/services and puts there all services file into one shared META-INF/services folder, so that only one file per service can be there. And it indeed by default puts the org.hibernate.bytecode.spi.BytecodeProvider from my application with no-op org.hibernate.bytecode.internal.none.BytecodeProviderImpl implementation defined there. But even if it would put the hinbernate-core default ByteBuddy implementation, I could use filtering feature of the maven-shade-plugin to exclude it

<filters>

   <filter>

      <artifact>*:*</artifact>

      <excludes>

         <exclude>META-INF/services/org.hibernate.bytecode.spi.BytecodeProvider
    
      </exclude>

   </excludes>

 </filter>

</filters>

which will then default to no op implementation, if ServiceLoader doesn’t find any implementation.

So now I have created a working application using GraalVM Native Image (with GraalVM 25.0.2. version), Hibernate 7.2.4, Hikari Pool and PostgreSQL database without any frameworks (like Spring Boot), even running on AWS Lambda, see my sample application. I use Amazon Aurora DSQL database, but it will work with any PostgreSQL-compatible database with some small changes in the pom.xml (use the classic postgresql driver instead of Aurora JDBC connector which is only sutable for this database) and IaC (template.yaml as I use AWS SAM). It’s a bit fragile and can break with each dependency update like updating to the newer Hibernate version, but with some patience it can hopefully be fixed.

You can boot Hibernate ORM and override the ClassLoaderService to influence the resolution of the BytecodeProvider if you want. There is an open issue you can track (HHH-19530) to move out the code into a separate artifact, since Quarkus has to do similar things to make this work. Either way, Quarkus is the proof that this can be done, so if you’re hitting a problem I would suggest you to look into what Quarkus does.
We will not be able to help you replicate all the delicate details that the Quarkus Hibernate ORM integration does to make this work for native compilation.

Thanks @beikov. As I wrote above, I found the solution how ti mitigate this. Greetings from Bonn, as I see that you supposed to based there as well.

1 Like