Repository: quarkusio/quarkus
Issue: Injection of @ConfigProperty double produces java.lang.ClassNotFoundException: double

If I add injection of a double field to the application-configuration quickstart solution GreetingResource:

```java
@Path("/greeting")
public class GreetingResource {

    @ConfigProperty(name = "greeting.message")
    String message;

    @ConfigProperty(name = "greeting.suffix", defaultValue="!")
    String suffix;

    @ConfigProperty(name = "greeting.name")
    Optional<String> name;

    @ConfigProperty(name = "greeting.math-pi-double")
    double decimalPi;
```

and then try to

```bash
java.lang.ClassNotFoundException: double
	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)
	at io.quarkus.deployment.steps.ConfigBuildStep$validateConfigProperties5.deploy(Unknown Source)
	at io.quarkus.runner.ApplicationImpl1.doStart(Unknown Source)
	at io.quarkus.runtime.Application.start(Application.java:93)
	at io.quarkus.runner.RuntimeRunner.run(RuntimeRunner.java:119)
	at io.quarkus.test.junit.QuarkusTestExtension.doJavaStart(QuarkusTestExtension.java:196)
	at io.quarkus.test.junit.QuarkusTestExtension.beforeAll(QuarkusTestExtension.java:80)
	at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$invokeBeforeAllCallbacks$8(ClassTestDescriptor.java:361)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.invokeBeforeAllCallbacks(ClassTestDescriptor.java:361)
	at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.before(ClassTestDescriptor.java:197)
	at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.before(ClassTestDescriptor.java:77)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:132)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
```

The problem is the generated ConfigBuildStep$validateConfigProperties5 attempting to load a primitive class using Class.forName:

```java
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package io.quarkus.deployment.steps;

import io.quarkus.arc.runtime.ConfigDeploymentTemplate;
import io.quarkus.runtime.StartupContext;
import io.quarkus.runtime.StartupTask;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

// $FF: synthetic class
public class ConfigBuildStep$validateConfigProperties5 implements StartupTask {
    public ConfigBuildStep$validateConfigProperties5() {
    }

    public void deploy(StartupContext var1) {
        ConfigDeploymentTemplate var13 = new ConfigDeploymentTemplate();
        HashMap var7 = new HashMap();
        HashSet var4 = new HashSet();
        ClassLoader var2 = Thread.currentThread().getContextClassLoader();
        Class var3 = Class.forName("java.lang.Double", (boolean)1, var2);
        ((Collection)var4).add(var3);
        ClassLoader var5 = Thread.currentThread().getContextClassLoader();
        Class var6 = Class.forName("java.lang.String", (boolean)1, var5);
        ((Collection)var4).add(var6);
        ((Map)var7).put("greeting.math-pi", var4);
        HashSet var9 = new HashSet();
        ClassLoader var8 = Thread.currentThread().getContextClassLoader();
        Class var10 = Class.forName("double", (boolean)1, var8);
        ((Collection)var9).add(var10);
        ((Map)var7).put("greeting.math-pi-double", var9);
        HashSet var11 = new HashSet();
        ((Collection)var11).add(var6);
        ((Map)var7).put("greeting.message", var11);
        HashSet var12 = new HashSet();
        ((Collection)var12).add(var6);
        ((Map)var7).put("greeting.unique", var12);
        var13.validateConfigProperties((Map)var7);
    }
}
```

We have to catch the use of a primitive type and reference the prmitive.class value directly.


Changed files:
core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/TestTemplate.java
core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java
core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java

diff --git a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java
index 93e13c2c565..381fd434841 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java
@@ -397,16 +397,23 @@ private ResultHandle loadObjectInstance(MethodCreator method, Object param, Map<
             out = method.invokeVirtualMethod(ofMethod(StartupContext.class, "getValue", Object.class, String.class),
                     method.getMethodParam(0), method.load(proxyId));
         } else if (param instanceof Class<?>) {
-            String name = classProxies.get(param);
-            if (name == null) {
-                name = ((Class) param).getName();
+            if (!((Class) param).isPrimitive()) {
+                // Only try to load the class by name if it is not a primitive class
+                String name = classProxies.get(param);
+                if (name == null) {
+                    name = ((Class) param).getName();
+                }
+                ResultHandle currentThread = method.invokeStaticMethod(ofMethod(Thread.class, "currentThread", Thread.class));
+                ResultHandle tccl = method.invokeVirtualMethod(
+                        ofMethod(Thread.class, "getContextClassLoader", ClassLoader.class),
+                        currentThread);
+                out = method.invokeStaticMethod(
+                        ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class),
+                        method.load(name), method.load(true), tccl);
+            } else {
+                // Else load the primitive type by reference; double.class => Class var9 = Double.TYPE;
+                out = method.loadClass((Class) param);
             }
-            ResultHandle currentThread = method.invokeStaticMethod(ofMethod(Thread.class, "currentThread", Thread.class));
-            ResultHandle tccl = method.invokeVirtualMethod(ofMethod(Thread.class, "getContextClassLoader", ClassLoader.class),
-                    currentThread);
-            out = method.invokeStaticMethod(
-                    ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class),
-                    method.load(name), method.load(true), tccl);
         } else if (expectedType == boolean.class) {
             out = method.load((boolean) param);
         } else if (expectedType == Boolean.class) {
diff --git a/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java
index bcfef309fff..4801e56a4ad 100644
--- a/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java
+++ b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java
@@ -3,6 +3,7 @@
 import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT;
 
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 
 import org.jboss.jandex.AnnotationInstance;
@@ -13,9 +14,7 @@
 
 import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem;
 import io.quarkus.arc.deployment.BeanContainerBuildItem;
-import io.quarkus.arc.deployment.BeanContainerListenerBuildItem;
 import io.quarkus.arc.deployment.BeanDefiningAnnotationBuildItem;
-import io.quarkus.arc.runtime.BeanContainerListener;
 import io.quarkus.deployment.annotations.BuildProducer;
 import io.quarkus.deployment.annotations.BuildStep;
 import io.quarkus.deployment.annotations.ExecutionTime;
@@ -23,7 +22,6 @@
 import io.quarkus.deployment.builditem.FeatureBuildItem;
 import io.quarkus.deployment.builditem.LaunchModeBuildItem;
 import io.quarkus.deployment.builditem.ServiceStartBuildItem;
-import io.quarkus.deployment.recording.RecorderContext;
 import io.quarkus.extest.runtime.IConfigConsumer;
 import io.quarkus.extest.runtime.ObjectOfValue;
 import io.quarkus.extest.runtime.ObjectValueOf;
@@ -32,7 +30,6 @@
 import io.quarkus.extest.runtime.TestBuildTimeConfig;
 import io.quarkus.extest.runtime.TestRunTimeConfig;
 import io.quarkus.extest.runtime.TestTemplate;
-import io.quarkus.runtime.RuntimeValue;
 
 /**
  * A test extension deployment processor
@@ -199,6 +196,32 @@ void configureBeans(TestTemplate template, List<TestBeanBuildItem> testBeans, Be
         }
     }
 
+    /**
+     * Test for https://github.com/quarkusio/quarkus/issues/1633
+     * 
+     * @param template - runtime template
+     */
+    @BuildStep
+    @Record(RUNTIME_INIT)
+    void referencePrimitiveTypeClasses(TestTemplate template) {
+        HashSet<Class<?>> allPrimitiveTypes = new HashSet<>();
+        allPrimitiveTypes.add(byte.class);
+        allPrimitiveTypes.add(char.class);
+        allPrimitiveTypes.add(short.class);
+        allPrimitiveTypes.add(int.class);
+        allPrimitiveTypes.add(long.class);
+        allPrimitiveTypes.add(float.class);
+        allPrimitiveTypes.add(double.class);
+        allPrimitiveTypes.add(byte[].class);
+        allPrimitiveTypes.add(char[].class);
+        allPrimitiveTypes.add(short[].class);
+        allPrimitiveTypes.add(int[].class);
+        allPrimitiveTypes.add(long[].class);
+        allPrimitiveTypes.add(float[].class);
+        allPrimitiveTypes.add(double[].class);
+        template.validateTypes(allPrimitiveTypes);
+    }
+
     @BuildStep
     @Record(RUNTIME_INIT)
     ServiceStartBuildItem boot(LaunchModeBuildItem launchMode) {
diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/TestTemplate.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/TestTemplate.java
index 6b2da7a1e2f..feaed1d322b 100644
--- a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/TestTemplate.java
+++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/TestTemplate.java
@@ -1,5 +1,7 @@
 package io.quarkus.extest.runtime;
 
+import java.util.Set;
+
 import org.jboss.logging.Logger;
 
 import io.quarkus.arc.runtime.BeanContainer;
@@ -15,12 +17,12 @@ public class TestTemplate {
     /**
      * Instantiate the given class in the given BeanContainer and passes the TestBuildAndRunTimeConfig and TestRunTimeConfig to
      * it
-     * 
-     * @see IConfigConsumer#loadConfig(TestBuildAndRunTimeConfig, TestRunTimeConfig)
+     *
      * @param beanContainer - CDI container
      * @param beanClass - IConfigConsumer
      * @param buildTimeConfig - the extension TestBuildAndRunTimeConfig
      * @param runTimeConfig - the extension TestRunTimeConfig
+     * @see IConfigConsumer#loadConfig(TestBuildAndRunTimeConfig, TestRunTimeConfig)
      */
     public void configureBeans(BeanContainer beanContainer, Class<IConfigConsumer> beanClass,
             TestBuildAndRunTimeConfig buildTimeConfig,
@@ -30,4 +32,15 @@ public void configureBeans(BeanContainer beanContainer, Class<IConfigConsumer> b
         instance.loadConfig(buildTimeConfig, runTimeConfig);
         log.infof("configureBeans, instance=%s\\n", instance);
     }
+
+    /**
+     * Access the primitive class types at runtime to validate the build step generated deploy method
+     * 
+     * @param typesSet
+     */
+    public void validateTypes(Set<Class<?>> typesSet) {
+        for (Class<?> type : typesSet) {
+            log.infof("Checking type: %s", type.getName());
+        }
+    }
 }