Nullable types in kotlin annotation processor

Gil Goldzweig :

I'm working on annotation processor for Kotlin and because the processed elements are in Java I don't receive nullables as ? instead with a @Nullable annotation and that's fine, but I'm facing a problem with receiving null parameters in types and in higher order functions, for normal parameters.

var someNullField: String? = "" 

I will receive java.lang.String at process with @org.jetbrains.annotations.Nullable in its annotations.

But List<String?> for example will return me java.util.List<java.lang.String> without any annotations not in the main element not in the type arguments which results in a unknown nullability state

I tried using javax.lang.model.util.Types to find some sort of result but nothing.

Some of the code that i'm using now:

val utils = processingEnvironment.typeUtils
val type = fieldElement.asType()
if (type is DeclaredType) {
    val typeElement = utils.asElement(type)
    type.typeArguments
            .forEach {
                //Trying different ways and just printing for possible results
                val capture = utils.capture(it)
                val erasure = utils.erasure(it)
                val element = utils.asElement(it)
                printMessage("element: $element isNullable: ${element.isNullable()} isNotNull: ${element.isNotNull()}\ncapture: $capture isNullable: ${capture.isNullable()} isNotNull: ${capture.isNotNull()}\nerasure: $erasure isNullable: ${erasure.isNullable()} isNotNull: ${erasure.isNotNull()}")
            }
}

All help will be appreciated.

user1643723 :

A bit of necessary history: as of Java 6 (when the Mirror API was made public) Java annotations could not be used on anything, but the same kinds of top-level elements, accessible via reflection. You could annotate classes, methods and fields, but could not annotate type arguments (List<String>) or local variables (String value = ...). Sun/Oracle engineers have acknowledged that limitation, and in Java 8 the so-called "type annotations" were born.

Type annotations can target type of anything: type of local variable, array component type, type variable type and even return type (later annotation is placed similarly, but is distinct from the old-school annotations on the method!). Type annotations are created via new @Target value: ElementType#TYPE_USE.

When Kotlin people write

List<String?>

That really means

List<@Nullable String>

which can be read as: "the list of nullable String elements".

Since the type itself is being targeted, you are expected to obtain annotations by examining it's original TypeMirror (don't bother with erased or captured TypeMirrors, they don't have enough connection to source code to retain the annotations). Coincidentally, the Mirror API was refactored, resulting in the new interface AnnotatedConstruct, and conveniently making TypeMirror it's descendant.


Now the bad news: by the time of Java 8 release the support for inspecting type annotations apparently wasn't production-ready, so it got butchered. The JSR has been rewritten to imply, that "TypeMirror#getAnnotationMirrors" is supposed to return nothing.

The bits of support, that were removed from public API, are still available via Oracle's vendor-specific Tree API (supported in javac only). The TypeMirror, returned by Tree#getTypeMirror may contain the annotation the way you are expecting it to. But since it is buggy, you will only be able to get annotations via series of hacks, and ultimately, this won't work at all times (such as in case of nested type arguments). See this question for some research in that direction.

The fix for that mess was merged in Java 9. I haven't tested it yet, but it looks like TypeMirror#getAnnotationMirrors might finally work. There are no plans to backport the fix to the older Java version.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=457598&siteId=1