When setting spring.jmx.enabled to true in a Spring Boot application and building a native image the native image fails with the following exception during startup:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mbeanExporter': Instantiation of supplied bean failed
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1220) ~[demo:6.0.10]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1158) ~[demo:6.0.10]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560) ~[demo:6.0.10]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) ~[demo:6.0.10]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[demo:6.0.10]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[demo:6.0.10]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[demo:6.0.10]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[demo:6.0.10]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) ~[demo:6.0.10]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:941) ~[demo:6.0.10]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:608) ~[demo:6.0.10]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) ~[demo:3.1.1]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:436) ~[demo:3.1.1]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) ~[demo:3.1.1]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[demo:3.1.1]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[demo:3.1.1]
        at com.example.demo.DemoApplication.main(DemoApplication.java:10) ~[demo:na]
Caused by: java.lang.IllegalArgumentException: Only values of autodetect constants allowed
        at org.springframework.jmx.export.MBeanExporter.setAutodetectMode(MBeanExporter.java:237) ~[demo:6.0.10]
        at org.springframework.jmx.export.annotation.AnnotationMBeanExporter.<init>(AnnotationMBeanExporter.java:51) ~[demo:6.0.10]
        at org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration.mbeanExporter(JmxAutoConfiguration.java:68) ~[demo:3.1.1]
        at org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration__BeanDefinitions.lambda$getMbeanExporterInstanceSupplier$1(JmxAutoConfiguration__BeanDefinitions.java:40) ~[na:na]
        at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:68) ~[demo:6.0.10]
        at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:54) ~[demo:6.0.10]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$get$2(BeanInstanceSupplier.java:200) ~[na:na]
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) ~[demo:6.0.10]
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) ~[demo:6.0.10]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.invokeBeanSupplier(BeanInstanceSupplier.java:212) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:200) ~[na:na]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:947) ~[demo:6.0.10]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1214) ~[demo:6.0.10]
        ... 16 common frames omitted

This is due to missing reflection configuration on fields of MBeanExporter, which is required by the new Constants(MBeanExporter.class) call here: https://github.com/spring-projects/spring-framework/blob/main/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java#L142

After adding a reflection-configuration.json with the following content to the application the error no longer occurs:

[
    {
        "name": "org.springframework.jmx.export.MBeanExporter",
        "allDeclaredFields": true
    }
]

Is it reasonable to add this reflection configuration to Spring?

Steps to reproduce

  • Initialize a new Spring Boot app with Native Image support using Spring Initializr
  • Set spring.jmx.enabled: true in application.properties
  • Build native image using mvn native:compile -Pnative
  • Start the application and observe the exception

Comment From: sbrannen

Is it reasonable to add this reflection configuration to Spring?

If we wish to continue using Constants for MBeanExporter, then yes.

However, I think we should consider a different approach to Constants that does not require reflection -- for example, using an enum internally with a mapping from the existing constants to enum constants.

Comment From: sbrannen

However, I think we should consider a different approach to Constants that does not require reflection -- for example, using an enum internally with a mapping from the existing constants to enum constants.

Since Constants is an outdated mechanism that predates enum support introduced in Java 5, we plan to revise the internals of MBeanExporter to avoid the use of reflection via Constants.

In light of that, I have changed the title of this issue.

Comment From: sbrannen

Update

  • 6.0.11: This issue will address the need for reflection hints in a GraalVM native image.
  • 6.1: #30851

Comment From: sbrannen

@beckermarc, the changes to MBeanExporter will be available in upcoming 6.0.11 snapshots.

If you can verify that the changes work for you with 6.0.11 snapshots, we'd be grateful!

Otherwise, please give it a try once 6.0.11 has been released.

Thanks

Comment From: beckermarc

Thanks @sbrannen! 🚀 I was able to confirm that the reflection metadata is no longer required with a 6.0.11 snapshot

Comment From: sbrannen

I was able to confirm that the reflection metadata is no longer required with a 6.0.11 snapshot

Great!

Thanks so much for confirming this, @beckermarc. 👍