Repository: quarkusio/quarkus
Issue: NPE from ArcAnnotationProcessor when default value() is used

Hello @mkouba ,

This is in regards to the issue we discussed today on Zulip.

After using `jandex-maven-plugin` to generate `META-INF/jandex.idx` I'm getting errors from all my tests.

Maven plugin I used:

```xml
<plugin>
  <groupId>org.jboss.jandex</groupId>
  <artifactId>jandex-maven-plugin</artifactId>
  <version>1.0.5</version>
  <executions>
    <execution>
      <id>make-index</id>
      <goals>
        <goal>jandex</goal>
      </goals>
    </execution>
  </executions>
</plugin>
```

And the stack trace I'm getting is:

```plain
Caused by: java.lang.NullPointerException: Value not set for java.lang.Class<? extends akka.actor.Actor> value()
    at io.quarkus.arc.processor.AnnotationLiteralProcessor.process(AnnotationLiteralProcessor.java:92)
    at io.quarkus.arc.processor.BeanGenerator.initConstructor(BeanGenerator.java:624)
    at io.quarkus.arc.processor.BeanGenerator.createConstructor(BeanGenerator.java:513)
    at io.quarkus.arc.processor.BeanGenerator.generateProducerMethodBean(BeanGenerator.java:371)
    at io.quarkus.arc.processor.BeanGenerator.generate(BeanGenerator.java:124)
    at io.quarkus.arc.processor.BeanProcessor.process(BeanProcessor.java:186)
    at io.quarkus.arc.deployment.ArcAnnotationProcessor.build(ArcAnnotationProcessor.java:259)
```

The source code (at revision with jandex failure):

https://github.com/sarxos/abberwoult/tree/00dd5d0a182f8ea85657044a4e4a228a7d828756

The problematic annotation is this buddy here:

```java
@Qualifier
@Documented
@Target({ FIELD, PARAMETER, METHOD })
@Retention(RUNTIME)
public @interface ActorByClass {

	final Class<? extends Actor> NO_CLASS = Actor.class;

	@Nonbinding
	Class<? extends Actor> value() default Actor.class;
}
```

After you suggested to override jandex dependency in corresponding maven plugin to 2.1.1.Final all tests are again passing, which proves that `jandex-maven-plugin` uses outdated dependency.

The workarounds so far:

1) Use empty `META-INF/beans.xml` instead of `jandex-maven-plugin`, or
2) Force newer (2.1.1.Final) jandex dependency in `jandex-maven-plugin`:

```xml
<plugin>
  <groupId>org.jboss.jandex</groupId>
  <artifactId>jandex-maven-plugin</artifactId>
  <version>1.0.5</version>
  <executions>
    <execution>
      <id>make-index</id>
      <goals>
        <goal>jandex</goal>
      </goals>
    </execution>
  </executions>
  <dependencies>
    <dependency>
      <groupId>org.jboss</groupId>
      <artifactId>jandex</artifactId>
      <version>2.1.1.Final</version>
    </dependency>
  </dependencies>
</plugin>
```


Changed files:
independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralGenerator.java
independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java
core/deployment/src/main/java/io/quarkus/deployment/index/ApplicationArchiveBuildStep.java

diff --git a/core/deployment/src/main/java/io/quarkus/deployment/index/ApplicationArchiveBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/index/ApplicationArchiveBuildStep.java
index efbb6c1ffe3..d1ad9fa9aa9 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/index/ApplicationArchiveBuildStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/index/ApplicationArchiveBuildStep.java
@@ -29,7 +29,6 @@
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.List;
@@ -64,6 +63,9 @@ public class ApplicationArchiveBuildStep {
 
     private static final String JANDEX_INDEX = "META-INF/jandex.idx";
 
+    // At least Jandex 2.1 is needed
+    private static final int REQUIRED_INDEX_VERSION = 8;
+
     IndexDependencyConfiguration config;
 
     @ConfigRoot(phase = ConfigPhase.BUILD_TIME)
@@ -162,7 +164,6 @@ private static Collection<? extends Path> getMarkerFilePaths(ClassLoader classLo
                 ret.add(urlToPath(url));
             }
         }
-
         return ret;
     }
 
@@ -187,11 +188,19 @@ private static Index handleFilePath(Path path) throws IOException {
         Path existing = path.resolve(JANDEX_INDEX);
         if (Files.exists(existing)) {
             try (FileInputStream in = new FileInputStream(existing.toFile())) {
-                IndexReader r = new IndexReader(in);
-                return r.read();
+                IndexReader reader = new IndexReader(in);
+                if (reader.getIndexVersion() < REQUIRED_INDEX_VERSION) {
+                    LOGGER.warnf("Re-indexing %s - at least Jandex 2.1 must be used to index an application dependency", path);
+                    return indexFilePath(path);
+                } else {
+                    return reader.read();
+                }
             }
         }
+        return indexFilePath(path);
+    }
 
+    private static Index indexFilePath(Path path) throws IOException {
         Indexer indexer = new Indexer();
         try (Stream<Path> stream = Files.walk(path)) {
             stream.forEach(path1 -> {
@@ -208,23 +217,32 @@ private static Index handleFilePath(Path path) throws IOException {
     }
 
     private static Index handleJarPath(Path path) throws IOException {
-        Indexer indexer = new Indexer();
         try (JarFile file = new JarFile(path.toFile())) {
             ZipEntry existing = file.getEntry(JANDEX_INDEX);
             if (existing != null) {
                 try (InputStream in = file.getInputStream(existing)) {
-                    IndexReader r = new IndexReader(in);
-                    return r.read();
+                    IndexReader reader = new IndexReader(in);
+                    if (reader.getIndexVersion() < REQUIRED_INDEX_VERSION) {
+                        LOGGER.warnf("Re-indexing %s - at least Jandex 2.1 must be used to index an application dependency",
+                                path);
+                        return indexJar(file);
+                    } else {
+                        return reader.read();
+                    }
                 }
             }
+            return indexJar(file);
+        }
+    }
 
-            Enumeration<JarEntry> e = file.entries();
-            while (e.hasMoreElements()) {
-                JarEntry entry = e.nextElement();
-                if (entry.getName().endsWith(".class")) {
-                    try (InputStream inputStream = file.getInputStream(entry)) {
-                        indexer.index(inputStream);
-                    }
+    private static Index indexJar(JarFile file) throws IOException {
+        Indexer indexer = new Indexer();
+        Enumeration<JarEntry> e = file.entries();
+        while (e.hasMoreElements()) {
+            JarEntry entry = e.nextElement();
+            if (entry.getName().endsWith(".class")) {
+                try (InputStream inputStream = file.getInputStream(entry)) {
+                    indexer.index(inputStream);
                 }
             }
         }
diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralGenerator.java
index b1b8a9b71d9..4c8fd622a36 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralGenerator.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralGenerator.java
@@ -46,7 +46,6 @@
 import org.jboss.jandex.ClassInfo;
 import org.jboss.jandex.DotName;
 import org.jboss.jandex.MethodInfo;
-import org.jboss.jandex.PrimitiveType;
 import org.jboss.jandex.Type;
 import org.jboss.logging.Logger;
 
@@ -114,14 +113,10 @@ static void createSharedAnnotationLiteral(ClassOutput classOutput, Key key, Lite
     }
 
     static void createAnnotationLiteral(ClassOutput classOutput, ClassInfo annotationClass,
-            AnnotationInstance annotationInstance, String literalName) {
-        createAnnotationLiteral(classOutput, annotationClass, annotationInstance.values(), literalName);
-    }
-
-    static void createAnnotationLiteral(ClassOutput classOutput, ClassInfo annotationClass, List<AnnotationValue> values,
+            AnnotationInstance annotationInstance,
             String literalName) {
 
-        Map<String, AnnotationValue> annotationValues = values.stream()
+        Map<String, AnnotationValue> annotationValues = annotationInstance.values().stream()
                 .collect(Collectors.toMap(AnnotationValue::name, Function.identity()));
 
         // Ljavax/enterprise/util/AnnotationLiteral<Lcom/foo/MyQualifier;>;Lcom/foo/MyQualifier;
@@ -142,45 +137,12 @@ static void createAnnotationLiteral(ClassOutput classOutput, ClassInfo annotatio
             if (value == null) {
                 value = method.defaultValue();
             }
-            ResultHandle retValue = null;
             if (value == null) {
-                switch (method.returnType().kind()) {
-                    case CLASS:
-                    case ARRAY:
-                        retValue = valueMethod.loadNull();
-                        break;
-                    case PRIMITIVE:
-                        PrimitiveType primitiveType = method.returnType().asPrimitiveType();
-                        switch (primitiveType.primitive()) {
-                            case BOOLEAN:
-                                retValue = valueMethod.load(false);
-                                break;
-                            case BYTE:
-                            case SHORT:
-                            case INT:
-                                retValue = valueMethod.load(0);
-                                break;
-                            case LONG:
-                                retValue = valueMethod.load(0L);
-                                break;
-                            case FLOAT:
-                                retValue = valueMethod.load(0.0f);
-                                break;
-                            case DOUBLE:
-                                retValue = valueMethod.load(0.0d);
-                                break;
-                            case CHAR:
-                                retValue = valueMethod.load('\\u0000');
-                                break;
-                        }
-                        break;
-                    default:
-                        break;
-                }
-            } else {
-                retValue = loadValue(valueMethod, value, annotationClass, method);
+                throw new IllegalStateException(String.format(
+                        "Value is not set for %s.%s(). Most probably an older version of Jandex was used to index an application dependency. Make sure that Jandex 2.1+ is used.",
+                        method.declaringClass().name(), method.name()));
             }
-            valueMethod.returnValue(retValue);
+            valueMethod.returnValue(loadValue(valueMethod, value, annotationClass, method));
         }
         annotationLiteral.close();
         LOGGER.debugf("Annotation literal generated: %s", literalName);
diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java
index a37559f21f0..8c6d0436b88 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java
@@ -89,7 +89,9 @@ ResultHandle process(BytecodeCreator bytecode, ClassOutput classOutput, ClassInf
                     value = method.defaultValue();
                 }
                 if (value == null) {
-                    throw new NullPointerException("Value not set for " + method);
+                    throw new IllegalStateException(String.format(
+                            "Value is not set for %s.%s(). Most probably an older version of Jandex was used to index an application dependency. Make sure that Jandex 2.1+ is used.",
+                            method.declaringClass().name(), method.name()));
                 }
                 ResultHandle retValue = AnnotationLiteralGenerator.loadValue(bytecode, value, annotationClass, method);
                 constructorParams[iterator.previousIndex()] = retValue;