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:
- take the type of the 0th parameter, it must be a parameterized type, and take the 0th type argument
- 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:
- take the type of the 0th parameter, it must be a parameterized type, and take the 0th type argument
- take the previously obtained type, it must be a wildcard type which is an argument of a parameterized type, and take its bound
- 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.