Repository: quarkusio/quarkus
Issue: NoClassDefFoundError for transitive dependency when using gradle quarkusDev

**Describe the bug**
When running a Quarkus application in dev mode, `NoClassDefFoundError` occurs for a class that is provided by a transitive dependency, i.e. by a dependency not declared in `build.gradle` but required indirectly by a declared dependency.

The error does not occur when the application is built with `gradle quarkusBuild --uber-jar` and run with `java -jar build/build/trans-dep-1.0.0-SNAPSHOT-runner.jar`.

**Expected behavior**
The application should work no matter if it is run in dev mode or not.

**Actual behavior**
If the application is started with `gradle quarkusDev`, an *internal server error* is returned when a request is made to a REST resource needing the transitive dependency to complete. Both the log and the HTTP response contain a stacktrace:

```
2020-05-03 14:24:58,572 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-1) HTTP Request to /hello failed, error id: 010f0882-0682-4c9e-bd7c-b8da19db6d42-1: org.jboss.resteasy.spi.UnhandledException: java.lang.NoClassDefFoundError: io/nayuki/qrcodegen/QrCode$Ecc
        at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:106)
        at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:372)
        at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:216)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:515)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:259)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:160)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:362)
        at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:163)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:245)
        at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:123)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.access$000(VertxRequestHandler.java:36)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:87)
        at io.quarkus.runtime.CleanableExecutor$CleaningRunnable.run(CleanableExecutor.java:231)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
        at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2046)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1578)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at java.base/java.lang.Thread.run(Thread.java:834)
        at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Caused by: java.lang.NoClassDefFoundError: io/nayuki/qrcodegen/QrCode$Ecc
        at net.codecrete.qrbill.generator.QRCode.draw(QRCode.java:49)
        at net.codecrete.qrbill.generator.BillLayout.drawPaymentPart(BillLayout.java:131)
        at net.codecrete.qrbill.generator.BillLayout.draw(BillLayout.java:94)
        at net.codecrete.qrbill.generator.QRBill.validateAndGenerate(QRBill.java:166)
        at net.codecrete.qrbill.generator.QRBill.generate(QRBill.java:113)
        at quarkus.issue.ExampleResource.hello(ExampleResource.java:45)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:167)
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
        at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:621)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:487)
        at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:437)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:362)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:439)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:400)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:374)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:67)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:488)
        ... 20 more
Caused by: java.lang.ClassNotFoundException: io.nayuki.qrcodegen.QrCode$Ecc
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:341)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:294)
        ... 41 more
```

**To Reproduce**
Steps to reproduce the behavior:
1. Fetch to sample project from https://github.com/manuelbl/trans-dep
2. Start the application using `gradle quarkusDev`
3. Open the URL http://localhost:8080/hello

**Configuration**
See sample project on GitHub. It is a minimal generated Quarkus project with as single additional dependency and a modified *hello* endpoint (see `ExampleResource`).

**Environment:**
 - Output of `uname -a` or `ver`: macOS Catalina 10.15.4
 - Output of `java -version`: java version "11.0.1" 2018-10-16 LTS
 - GraalVM version (if different from Java): n/a
 - Quarkus version or git rev: 1.4.1.Final
 - Build tool (ie. output of `mvnw --version` or `gradlew --version`): Gradle 6.3

**Additional context**
The class `io.nayuki.qrcodegen.QrCode$Ecc` (triggering the exception) is part of the library `io.nayuki:qrcodegen:1.6.0`. This library is a dependency of the library `net.codecrete.qrbill:qrbill-generator:2.2.2`, which is declared in `build.gradle`.

A dependency analysis with gradle shows that `io.nayuki:qrcodegen:1.6.0` is part of the *runtimeClasspath* but not of *compileClasspath*. This is correct. The library is not needed for compilation. It's needed at runtime only.

It would seem that `gradle quarkusDev` uses the wrong class path.


Changed files:
devtools/gradle/src/main/java/io/quarkus/gradle/AppModelGradleResolver.java

diff --git a/devtools/gradle/src/main/java/io/quarkus/gradle/AppModelGradleResolver.java b/devtools/gradle/src/main/java/io/quarkus/gradle/AppModelGradleResolver.java
index f84191d9540..3db90c079c3 100644
--- a/devtools/gradle/src/main/java/io/quarkus/gradle/AppModelGradleResolver.java
+++ b/devtools/gradle/src/main/java/io/quarkus/gradle/AppModelGradleResolver.java
@@ -139,14 +139,19 @@ public AppModel resolveModel(AppArtifact appArtifact) throws AppModelResolverExc
         Map<AppArtifactKey, AppDependency> versionMap = new HashMap<>();
         Map<ModuleIdentifier, ModuleVersionIdentifier> userModules = new HashMap<>();
 
-        final String classpathConfigName = launchMode == LaunchMode.NORMAL ? JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME
-                : launchMode == LaunchMode.TEST ? JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME
-                        : JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME;
+        final String classpathConfigName = launchMode == LaunchMode.TEST ? JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME
+                : JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME;
 
         collectDependencies(project.getConfigurations().getByName(classpathConfigName),
                 appBuilder, directExtensionDeps, userDeps,
                 versionMap, userModules);
 
+        if (launchMode == LaunchMode.DEVELOPMENT) {
+            collectDependencies(project.getConfigurations().getByName(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME),
+                    appBuilder, directExtensionDeps, userDeps,
+                    versionMap, userModules);
+        }
+
         final List<AppDependency> deploymentDeps = new ArrayList<>();
         final List<AppDependency> fullDeploymentDeps = new ArrayList<>(userDeps);
         if (!directExtensionDeps.isEmpty()) {