apache / camel-quarkus

Apache Camel Quarkus
https://camel.apache.org
Apache License 2.0
256 stars 189 forks source link

camel-quarkus-syslog not compatible with quarkus-jdbc-oracle extension in native mode #6291

Closed zakkak closed 2 months ago

zakkak commented 2 months ago

Bug description

Building a project with both camel-quarkus-syslog and quarkus-jdbc-oracle as dependencies results in build failures in native-mode. The output looks like this:

Fatal error: org.graalvm.compiler.debug.GraalError: org.graalvm.compiler.debug.GraalError: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Detected a MBean server in the image heap. This is currently not supported, but could be changed in the future. Management beans are registered in many global caches that would need to be cleared and properly re-built at image build time. Class of disallowed object: com.sun.jmx.mbeanserver.JmxMBeanServer Try to avoid initializing the class that stores a MBean server or a MBean in a static field
The culprit object has been instantiated by the 'oracle.jdbc.driver.OracleDriver' class initializer with the following trace:
    at com.sun.jmx.mbeanserver.JmxMBeanServer.<init>(JmxMBeanServer.java:225)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.newMBeanServer(JmxMBeanServer.java:1437)
    at javax.management.MBeanServerBuilder.newMBeanServer(MBeanServerBuilder.java:110)
    at javax.management.MBeanServerFactory.newMBeanServer(MBeanServerFactory.java:329)
    at javax.management.MBeanServerFactory.createMBeanServer(MBeanServerFactory.java:231)
    at javax.management.MBeanServerFactory.createMBeanServer(MBeanServerFactory.java:192)
    at java.lang.management.ManagementFactory.getPlatformMBeanServer(ManagementFactory.java:487)
    at oracle.jdbc.driver.OracleDriver.registerMBeans(OracleDriver.java:454)
    at oracle.jdbc.driver.OracleDriver$1.run(OracleDriver.java:293)
    at java.security.AccessController.executePrivileged(AccessController.java:778)
    at java.security.AccessController.doPrivileged(AccessController.java:319)
    at oracle.jdbc.driver.OracleDriver.<clinit>(OracleDriver.java:291)
The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
    at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.AnalysisFuture.setException(AnalysisFuture.java:49)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:322)
    at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.AnalysisFuture.ensureDone(AnalysisFuture.java:63)
    at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.heap.ImageHeapInstance.readFieldValue(ImageHeapInstance.java:110)
    at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.heap.ImageHeapScanner.onObjectReachable(ImageHeapScanner.java:472)
    at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.heap.SVMImageHeapScanner.onObjectReachable(SVMImageHeapScanner.java:156)
    at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.heap.ImageHeapScanner.lambda$markReachable$5(ImageHeapScanner.java:452)
    at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.heap.ImageHeapScanner.lambda$postTask$14(ImageHeapScanner.java:695)
    at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.executeCommand(CompletionExecutor.java:187)
    at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.lambda$executeService$0(CompletionExecutor.java:171)
    at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1423)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)
...

Reproducer

wget "https://code.quarkus.io/d?e=jdbc-oracle&e=org.apache.camel.quarkus%3Acamel-quarkus-syslog&cn=code.quarkus.io" -O code.zip
unzip code.zip
cd code-with-quarkus
./mvnw clean package -Dquarkus.native.additional-build-args=--trace-object-instantiation=com.sun.jmx.mbeanserver.JmxMBeanServer
jamesnetherton commented 2 months ago

Same issue if syslog is replaced by camel-quarkus-netty (which syslog depends on).

jamesnetherton commented 2 months ago

It might be related to commons-pool2. When it's removed, native compilation is successful.

zhfeng commented 2 months ago

Is there any detail about the naitve compiliation errors ?

jamesnetherton commented 2 months ago

I think I may have fixed it.

BaseGenericObjectPool in commons-pool2 has jmxRegister and jmxUnregister methods. Once substituted, compilation succeeds.

zhfeng commented 2 months ago

Nice work and it looks like we had the similar issue before

I had the same fix in quarkus-pooled-jms

zhfeng commented 2 months ago

@jamesnetherton it looks like an issue in commons-pool2, is there any better way to do the substitution? currently, it seems we add the same fix in the different extensions.

zhfeng commented 2 months ago

Or this issue only happen with the quarkus-jdbc-oracle?

jamesnetherton commented 2 months ago

currently, it seems we add the same fix in the different extensions

Hmmm - that's a problem then. Any substitutions added here could be made conditional on quarkus-pooled-jms not being on the runtime classpath.

Otherwise we'd need a common home for the code so it can be shared.

zakkak commented 2 months ago

That was fast! Thank you @jamesnetherton and @zhfeng.