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.
In Kotlin, there's a distinction between nullable and non-nullable types: Nullable types are variables that can hold null . Non-null types are variables that can't hold null .
public annotation Nullable. Denotes that a parameter, field or method return value can be null. When decorating a method call parameter, this denotes that the parameter can legitimately be null and the method will gracefully deal with it. Typically used on optional parameters.
Any is only a superclass of non-nullable types. This makes it possible to write code that requires a non-null instance of anything, and still benefit from the safety of the type-checker (unlike when using Java's Object ).
You can use the "?. let" operator in Kotlin to check if the value of a variable is NULL. It can only be used when we are sure that we are refereeing to a non-NULL able value. The following example demonstrates how this operator works.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With