New Spring Boot 3.0.0-RC2 application with spring-boot-starter-actuator results in the following error:

2022-11-15T15:38:18.962+01:00 ERROR 95910 --- [           main] o.s.boot.SpringApplication               : Application run failed

java.lang.IllegalArgumentException: javax.management.NotCompliantMBeanException: com.sun.management.GarbageCollectorMXBean: Method com.sun.management.GarbageCollectorMXBean.getLastGcInfo has parameter or return type that cannot be translated into an open type
        at java.management@17.0.5/javax.management.StandardMBean.<init>(StandardMBean.java:271) ~[spring-boot-native-test:na]
        at java.management@17.0.5/javax.management.StandardEmitterMBean.<init>(StandardEmitterMBean.java:148) ~[spring-boot-native-test:na]
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk.management.ManagementSupport.addMXBean(ManagementSupport.java:299) ~[na:na]
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk.management.ManagementSupport.getPlatformMBeanServer(ManagementSupport.java:285) ~[na:na]
        at java.management@17.0.5/java.lang.management.ManagementFactory.getPlatformMBeanServer(ManagementFactory.java:45) ~[na:na]
        at io.micrometer.core.instrument.binder.tomcat.TomcatMetrics.getMBeanServer(TomcatMetrics.java:98) ~[na:na]
        at io.micrometer.core.instrument.binder.tomcat.TomcatMetrics.<init>(TomcatMetrics.java:72) ~[na:na]
        at org.springframework.boot.actuate.metrics.web.tomcat.TomcatMetricsBinder.onApplicationEvent(TomcatMetricsBinder.java:63) ~[spring-boot-native-test:3.0.0-RC2]
        at org.springframework.boot.actuate.metrics.web.tomcat.TomcatMetricsBinder.onApplicationEvent(TomcatMetricsBinder.java:42) ~[spring-boot-native-test:3.0.0-RC2]
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176) ~[na:na]
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169) ~[na:na]
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143) ~[na:na]
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:413) ~[spring-boot-native-test:6.0.0-RC4]
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:370) ~[spring-boot-native-test:6.0.0-RC4]
        at org.springframework.boot.context.event.EventPublishingRunListener.started(EventPublishingRunListener.java:103) ~[spring-boot-native-test:3.0.0-RC2]
        at org.springframework.boot.SpringApplicationRunListeners.lambda$started$5(SpringApplicationRunListeners.java:76) ~[na:na]
        at java.base@17.0.5/java.lang.Iterable.forEach(Iterable.java:75) ~[spring-boot-native-test:na]
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118) ~[na:na]
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112) ~[na:na]
        at org.springframework.boot.SpringApplicationRunListeners.started(SpringApplicationRunListeners.java:76) ~[na:na]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) ~[spring-boot-native-test:3.0.0-RC2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[spring-boot-native-test:3.0.0-RC2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[spring-boot-native-test:3.0.0-RC2]
        at bootnative.SpringBootNativeTestApplication.main(SpringBootNativeTestApplication.java:12) ~[spring-boot-native-test:na]
Caused by: javax.management.NotCompliantMBeanException: com.sun.management.GarbageCollectorMXBean: Method com.sun.management.GarbageCollectorMXBean.getLastGcInfo has parameter or return type that cannot be translated into an open type
        at java.management@17.0.5/com.sun.jmx.mbeanserver.Introspector.throwException(Introspector.java:468) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.MBeanAnalyzer.<init>(MBeanAnalyzer.java:120) ~[spring-boot-native-test:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.MBeanAnalyzer.analyzer(MBeanAnalyzer.java:102) ~[spring-boot-native-test:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.MXBeanIntrospector.getAnalyzer(MXBeanIntrospector.java:74) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.MBeanIntrospector.getPerInterface(MBeanIntrospector.java:192) ~[spring-boot-native-test:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.MBeanSupport.<init>(MBeanSupport.java:138) ~[spring-boot-native-test:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.MXBeanSupport.<init>(MXBeanSupport.java:66) ~[na:na]
        at java.management@17.0.5/javax.management.StandardMBean.construct(StandardMBean.java:175) ~[spring-boot-native-test:na]
        at java.management@17.0.5/javax.management.StandardMBean.<init>(StandardMBean.java:269) ~[spring-boot-native-test:na]
        ... 23 common frames omitted
Caused by: java.lang.IllegalArgumentException: Method com.sun.management.GarbageCollectorMXBean.getLastGcInfo has parameter or return type that cannot be translated into an open type
        at java.management@17.0.5/com.sun.jmx.mbeanserver.ConvertingMethod.from(ConvertingMethod.java:46) ~[spring-boot-native-test:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.MXBeanIntrospector.mFrom(MXBeanIntrospector.java:84) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.MXBeanIntrospector.mFrom(MXBeanIntrospector.java:54) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.MBeanAnalyzer.initMaps(MBeanAnalyzer.java:137) ~[spring-boot-native-test:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.MBeanAnalyzer.<init>(MBeanAnalyzer.java:118) ~[spring-boot-native-test:na]
        ... 30 common frames omitted
Caused by: javax.management.openmbean.OpenDataException: Cannot convert type: com.sun.management.GcInfo
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.openDataException(DefaultMXBeanMappingFactory.java:1539) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.mappingForType(DefaultMXBeanMappingFactory.java:261) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.ConvertingMethod.<init>(ConvertingMethod.java:212) ~[spring-boot-native-test:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.ConvertingMethod.from(ConvertingMethod.java:41) ~[spring-boot-native-test:na]
        ... 34 common frames omitted
Caused by: javax.management.openmbean.OpenDataException: Cannot convert type: java.util.Map<java.lang.String, java.lang.management.MemoryUsage>
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.openDataException(DefaultMXBeanMappingFactory.java:1539) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.mappingForType(DefaultMXBeanMappingFactory.java:261) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeCompositeMapping(DefaultMXBeanMappingFactory.java:475) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeMapping(DefaultMXBeanMappingFactory.java:294) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.mappingForType(DefaultMXBeanMappingFactory.java:259) ~[na:na]
        ... 36 common frames omitted
Caused by: javax.management.openmbean.OpenDataException: Cannot convert type: java.lang.management.MemoryUsage
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.openDataException(DefaultMXBeanMappingFactory.java:1539) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.mappingForType(DefaultMXBeanMappingFactory.java:261) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeTabularMapping(DefaultMXBeanMappingFactory.java:364) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeParameterizedTypeMapping(DefaultMXBeanMappingFactory.java:406) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeMapping(DefaultMXBeanMappingFactory.java:297) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.mappingForType(DefaultMXBeanMappingFactory.java:259) ~[na:na]
        ... 39 common frames omitted
Caused by: javax.management.openmbean.OpenDataException: Can't map java.lang.management.MemoryUsage to an open data type
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeCompositeMapping(DefaultMXBeanMappingFactory.java:462) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeMapping(DefaultMXBeanMappingFactory.java:294) ~[na:na]
        at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.mappingForType(DefaultMXBeanMappingFactory.java:259) ~[na:na]
        ... 43 common frames omitted

Comment From: derkoe

For an example see the build for this PR adding spring-boot-starter-actuator: https://github.com/derkoe/spring-boot-native-test/pull/3 Build log: https://github.com/derkoe/spring-boot-native-test/actions/runs/3474213767/jobs/5807121800 (this builds a native image and then tries to start it which results in the error)

Comment From: sdeleuze

Could be related to https://github.com/oracle/graal/issues/4510 but I don't remember seeing such error with just spring-boot-starter-actuator added.

Comment From: wilkinsona

Thanks for raising this, @derkoe. I can reproduce the problem. I don't yet understand the difference between your app and our smoke tests that use spring-boot-starter-actuator and Tomcat. For example, I would expect https://github.com/spring-projects/spring-aot-smoke-tests/tree/main/boot/actuator-webmvc to fail in the same way.

Comment From: wilkinsona

If I remove Spring Data JPA from the application, the problem does not occur. That may explain why our smoke test doesn't fail in the same way.

Comment From: derkoe

Ahh - I see! Thanks for your investigation.

Maybe we can create a smoke-test that includes ~~all~~ many starters?

Comment From: wilkinsona

We intentionally have many smoke tests, each of which focuses on a specific area. This makes it easier to determine where a problem lies as it narrows down the possible causes. We do have other applications with a broader focus such as the PetClinic sample application which has a Spring Boot 3 branch that uses the native support. It uses Spring Data JPA, Actuator, Tomcat, etc, and doesn't appear to suffer from this problem.

Comment From: wilkinsona

The problem appears to be resolvable by adding some reflection hints, although each time it just moves onto a new problem. I've got the following hints thus far:

hints.reflection().registerType(java.lang.management.MemoryUsage.class, MemberCategory.INTROSPECT_PUBLIC_METHODS);
hints.reflection().registerType(java.lang.management.ThreadInfo.class, MemberCategory.INTROSPECT_PUBLIC_METHODS);
hints.reflection().registerType(java.lang.management.LockInfo.class, MemberCategory.INTROSPECT_PUBLIC_METHODS);
hints.reflection().registerType(java.lang.management.MonitorInfo.class, MemberCategory.INTROSPECT_PUBLIC_METHODS);

The app now fails with this error:

Caused by: javax.management.openmbean.OpenDataException: Can't map java.lang.StackTraceElement to an open data type
    at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeCompositeMapping(DefaultMXBeanMappingFactory.java:462)
    at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.makeMapping(DefaultMXBeanMappingFactory.java:294)
    at java.management@17.0.5/com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory.mappingForType(DefaultMXBeanMappingFactory.java:259)
    ... 47 more

Adding hints for java.lang.StackTraceElement will almost certainly allow things to move on to the next problem.

I'm not really sure what it tells us. IMO, an application shouldn't have to provide hints to get standard MBeans to work – GraalVM should take care of this automatically. I also don't understand why these hints aren't always needed. Perhaps figuring that out will help us to get to the bottom of it.

Comment From: wilkinsona

Looks like I gave up one hint too soon. The app starts successfully with the following hints:

hints.reflection().registerType(java.lang.management.MemoryUsage.class, MemberCategory.INTROSPECT_PUBLIC_METHODS);
hints.reflection().registerType(java.lang.management.ThreadInfo.class, MemberCategory.INTROSPECT_PUBLIC_METHODS);
hints.reflection().registerType(java.lang.management.LockInfo.class, MemberCategory.INTROSPECT_PUBLIC_METHODS);
hints.reflection().registerType(java.lang.management.MonitorInfo.class, MemberCategory.INTROSPECT_PUBLIC_METHODS);
hints.reflection().registerType(java.lang.StackTraceElement.class, MemberCategory.INTROSPECT_PUBLIC_METHODS);

Comment From: sdeleuze

I will have a deeper look and will provide a feedback, potentially with Bellsoft input who is working on the topic.

Comment From: wilkinsona

The reachability metadata for Hibernate Validator adds hints for the 5 classes above. PetClinic uses spring-boot-starter-validation so this may explain why it doesn't have this problem.

Comment From: wilkinsona

I think I understand this now.

The reachability metadata for Hibernate contains some entries that are sufficient to cause the various failures discussed above. The failures will occur as soon as ManagementFactory.getPlatformMBeanServer() is called, even as the first statement in the application's main method. This explains why the problem goes away when the Hibernate dependency is removed.

A dependency on Hibernate Validator also fixes the problem as its has reflection hints that, through sheer coincidence, complement Hibernate's. This explains why the problem is not see in PetClinic – it depends on both Hibernate and Hibernate Validator.

We're going to fix this by contributing some improvements to the reachability metadata. Specifically, the MBean-related entries should be removed from the metadata for hibernate-core. I have built the supplied reproducer with a locally updated copy of the metadata repository and it fixes the problem.

We may also contribute a change to the metadata for Hibernate Validator to remove its MBean-related entries. They appear to be benign, but we do not believe they belong there as Hibernate Validator doesn't make any use of MBeans as far as we know.

Comment From: wilkinsona

I've opened https://github.com/oracle/graalvm-reachability-metadata/pull/113 to fix the metadata for hibernate-core. Until it is merged and released, I would recommend using the 5 additional hints above.

Comment From: derkoe

Thx Andy - you are amazing!! My app now builds with the given hints: https://github.com/derkoe/spring-boot-native-test/pull/3