If jandex is present in an extension, the RouteBuilder beans created by a runtime extension appear to be duplicated
In my setup, I have an extension with the jandex plugin applied to it so that the JARs contain a jandex.idx file. The build steps appear to run correctly, and record correctly. However, at runtime, when a Quarkus app attempts to get beans of type RouteBuilder, the RouteBuilder beans belonging to that extension get duplicated, and the duplicate instance has not had its constructor run. This duplicate bean later causes a runtime exception.
This could be user error; perhaps you don't want jandex indexes created for Quarkus extensions intended for Camel? Or perhaps this is indeed a bug in the way that Quarkus and Camel interact.
To reproduce, roughly speaking:
- Create an extension and apply the jandex plugin to the runtime and deployment projects.
- Create an application with a test that attempts to use Camel's registry to retrieve the RouteBuilder beans.
I am using Quarkus 2.9.2.Final, Camel 3.16.0, and camel-quarkus 2.9.0.
A reproduction git repo will be linked once the issue is posted.
Example reproduction: https://github.com/jskillin-idt/apache-camel-quarkus-issues-3844
The branch "without-camel" tested that the same style of injection works without Camel in the middle.
I should probably mention that simply running "./gradlew build" is enough to reproduce the issue using the example reproduction.
Here is what should be seen from the test output (and then Gradle links a fuller test report complete with the standard output that has the full stack trace):
ExampleTest > test() FAILED
java.lang.RuntimeException at QuarkusTestExtension.java:632
Caused by: java.lang.RuntimeException at null:-1
Caused by: java.lang.RuntimeException at CamelBootstrapRecorder.java:47
Caused by: java.lang.RuntimeException at CamelMainRuntime.java:65
Caused by: java.lang.NullPointerException at ExampleRouteBuilder.java:17
If you don't want Camel Quarkus to automatically discover and bootstrap RouteBuilder implementations, then you can add some configuration to application.properties:
quarkus.camel.routes-discovery.enabled=false
It's not entirely clear what you're trying to accomplish with your extension. Camel Quarkus can take care of bootstrapping RouteBuilder and the CamelContext for you. So you don't strictly need to produce your own synthetic beans for them and write your own recorders etc.
Hey James,
I think the downfall of the minimal reproduction I created is it doesn't do a good job demonstrating the intent behind the design. What RouteBuilders are available is not known at the time of writing this code. The app will live in a different location and there will be many of them. The idea is that the extensions will build RouteBuilders in response to customized rules.
If we disable this bootstrapping that Camel does, is there additional work to do to replace that functionality? I can do more investigation on this as I'm somewhat new to this ecosystem.
is there additional work to do to replace that functionality
Yes, you become responsible for ensuring those routes are added to the CamelContext.
The project provides some BuildItems for various things that could be useful for you.
https://github.com/apache/camel-quarkus/tree/main/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi
Is it unexpected for a user of camel-quarkus to produce synthetic RouteBuilder beans for Camel to discover later? If so, does that mean that producing RouteBuilder's is invalid while "quarkus.camel.routes-discovery.enabled" is set to true?
Is it unexpected for a user of camel-quarkus to produce synthetic RouteBuilder beans for Camel to discover later
It's not a scenario that has ever been considered TBH.
Does that mean that producing RouteBuilder's is invalid while "quarkus.camel.routes-discovery.enabled" is set to true
Kind of. There are 2 competing forces at play here. The framework is automatically discovering & instantiating the RouteBuilder classes that are in your extension. Also since you also produce synthetic beans for them, they are discoverable via the Camel registry and hence they get added to the CamelContext. In a 'normal' app, folks would not have a RouteBuilder that they instantiate via a CDI producer method since it does not make much sense to do so.
The alternative to disabling routes discovery entirely would be to suppress Camel Quarkus from trying to instantiate your RouteBuilder classes by producing RoutesBuilderClassExcludeBuildItem. For example:
@BuildStep
RoutesBuilderClassExcludeBuildItem excludedRoutesDiscovery() {
return RoutesBuilderClassExcludeBuildItem.ofClass(ExampleRouteBuilder.class);
}
We could maybe investigate making things a bit simpler so that additional code / config is not needed in the future.