Today we support conditional dependencies (in the extension metadata) that are optional dependencies which can be injected/activated in case a certain condition is satisfied. Their purpose could be described as "enable this extension if all its required dependencies appear to be available on the classpath".
Looking at PR [1] though decoupling quarkus-spring-web from RESTEasy Classic, which introduces a breaking change by requiring users to add either quarkus-resteasy-jackson or quarkus-resteasy-jackson-reactive, I had some thoughts about enhancing our support for conditional dependencies to make the end user experience better. Although, it would make the Quarkus dependency model even darker magic. Here is one idea anyway.
We could define extensions that appear to be alternative implementations of the same functionality/spec in the Quarkus platform properties, which is a platform-specific configuration [2] that is available during the dependency resolution phase. For example (perhaps, not a very a good one but to give an idea), it could look something like this:
resteasy.blocking=io.quarkus:quarkus-resteasy-blocking
resteasy.reactive=io.quarkus:quarkus-resteasy-reactive
# defines the default resteasy impl
dependency-injection.default.resteasy=${resteasy.reactive}
# defines the condition to be satisfied for the default impl to be injected
dependency-injection.if-none-available.resteasy=${resteasy.reactive},${resteasy.blocking}
Then the io.quarkus:quarkus-resteasy could become an injection point by adding the following to its metadata (META-INF/quarkus-extension.properties):
# inject the default resteasy impl unless one of its flavors is already present on the classpath
inject-dependencies=resteasy
For projects with complex dependency graphs though it may become less straightforward for users, and even us, to figure how the final dependency tree got resolved. Injecting one default may affect what other injection points will be initialized with (which isn't bad but may be hard to understand the injection sequence). There will also be the conditional dependencies that we support today in the mix. Besides making `mvn dependency:tree` useless and requiring `quarkus:dependency-tree` instead (which is already recommended today, the Gradle side should be ok though), there could be multiple injection points defaulting to incompatible alternatives. For example, there could be quarkus-resteasy defaulting to the reactive impl bringing the reactive impl of the Jackson serializer and there could be something else defaulting to the blocking impl of the Jackson serializer, for example. In this case, we'll need to choose which injection point to resolve first as that one will either break or force the non-default alternative for the other injection point. Which is generally ok but the question is which injection point should get the priority. This could be made consistent with the default dependency version convergence rules in the underlying built system. But it just shows how complicated it could become and what it would take to debug this.
WDYT? Is it worth exploring it further?