smallrye / jandex

Java Annotation Indexer

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Jandex fails when indexing a Kotlin-generated class with certain type annotation

Ladicek opened this issue · comments

When indexing a Kotlin-compiled class that includes the following method:

fun foo(bar: List<List<@Valid String>>) {
}

Jandex fails with the following exception:

java.lang.IllegalArgumentException: Not a parameterized type!
	at org.jboss.jandex.Type.asParameterizedType(Type.java:248)
	at org.jboss.jandex.Indexer.resolveTypePath(Indexer.java:1256)
	at org.jboss.jandex.Indexer.resolveTypePath(Indexer.java:1263)
	at org.jboss.jandex.Indexer.resolveTypeAnnotation(Indexer.java:1105)
	at org.jboss.jandex.Indexer.resolveTypeAnnotations(Indexer.java:957)
	at org.jboss.jandex.Indexer.indexWithSummary(Indexer.java:2363)
	at org.jboss.jandex.Indexer.index(Indexer.java:2317)

Originally reported at quarkusio/quarkus#29376

Copy of my investigation in the original issue:

Okay so this one is interesting. The method

fun foo(bar: List<List<@Valid String>>) {
}

is compiled to a JVM method with the following Signature attribute:

(Ljava/util/List<+Ljava/util/List<Ljava/lang/String;>;>;)V

In Java syntax, this corresponds to

public final void foo(List<? extends List<@Valid String>> bar) {
}

The type annotation is compiled down to this:

    RuntimeVisibleTypeAnnotations:
      0: #15(): METHOD_FORMAL_PARAMETER, param_index=0, location=[TYPE_ARGUMENT(0), TYPE_ARGUMENT(0)]
        javax.validation.Valid

So the annotation is correctly attributed to the 1st (or 0th if you wish) parameter of the method, but the type annotation path is wrong.

The type annotation path is basically:

  1. take the type of the 0th parameter, it must be a parameterized type, and take the 0th type argument
  2. take the previously obtained type, it must be a parameterized type, and take the 0th type argument

The 2nd step fails -- because the type obtained in step 1 is a wildcard type, not a parameterized type. Remember that the type is effectively List<? extends List<@Valid String>>.

For the Java snippet above, javac emits the annotation like this:

    RuntimeVisibleTypeAnnotations:
      0: #38(): METHOD_FORMAL_PARAMETER, param_index=0, location=[TYPE_ARGUMENT(0), WILDCARD, TYPE_ARGUMENT(0)]
        javax.validation.Valid

Where the type annotation path is basically:

  1. take the type of the 0th parameter, it must be a parameterized type, and take the 0th type argument
  2. take the previously obtained type, it must be a wildcard type which is an argument of a parameterized type, and take its bound
  3. take the previously obtained type, it must be a parameterized type, and take the 0th type argument

That navigates to the String type correctly.

I agree Jandex shouldn't fail like this, but it can't be denied that the Kotlin compiler emits internally inconsistent bytecode. My opinion is that Jandex should just skip this type annotation.