- Type: Design proposal
- Author: Denis Zharkov
- Contributors: Andrey Breslav
- Status: Submitted
- Prototype: Not started
- Discussion: KEEP-99
- Related proposals: JSR-305 custom nullability qualifiers
Add a separate artifact containing meta-annotations covering use cases of ones from JSR-305.
- We need to put somewhere
@ApplyToTypeArgumentsAnnotation
meta-annotation (see the discussion). - There is a modules-related issue with JSR-305 and Java 9.
- It's worth simplifying the way how JSR-305 nullability meta-annotations are being used
and integrating them with Kotlin-specific meta annotations. Namely,
@UnderMigration
and@ApplyToTypeArguments
.
This section describes proposed semantics of the new annotations and partly the layout of resulting artifact.
Root package for this artifact will be kotlin.annotations.jvm
.
All classes/packages names are assumed to be placed in the package and only their
relative names are mentioned below.
In JSR-305, there is @TypeQualifier
annotation that allows to introduce custom qualifiers (like @Nonnull
).
But that kind of meta-meta level seems to be unnecessary to our needs (at least for now),
the Kotlin compiler supports only nullability qualifier
(and in the nearest future mutability might be supported as well).
So, there will only be fixed number of built-in qualifier annotations:
nullability.Nullable
nullability.NotNull
mutability.Mutable
mutability.ReadOnly
Their target set would be the following: ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE
NB: Having ElementType.TYPE_USE among their target is questionable since it's unknown how that would work with bytecode version 50.0 (JDK 1.6).
And semantics when being applied to types is just the same as for analogue
from org.jetbrains.annotations
(see more about types enhancement)
This proposal suggests to introduce meta.Alias
annotation which would affect the compiler
in a similar way that @TypeQualifierNickname
does.
In a basic version its declaration may look like
package kotlin.annotations.jvm.meta
@Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class Alias(val qualifier: KClass<*>)
and its usages is supposed to look like:
@Alias(kotlin.annotations.jvm.nullability.Nullable::class)
annotation class MyNullable
Thus, applying @MyNullable
should have the same effect as @Nullable
itself has.
Beside it, @MyNullable
may have @UnderMigration
annotation on it that would change its
migration status.
This section describes the way how the concept similar to JSR-305 default qualifiers semantics can be introduced.
We suggest to use a special enum class instead of ElementType
that is used as a parameter type for JSR-305 @TypeQualifierDefault
.
It might look like:
enum class ApplicabilityKind {
RETURN_TYPE, VALUE_PARAMETER, FIELD, TYPE_USE, TYPE_ARGUMENT
}
All elements should work just the same as relevant entries from ElementType
do for @TypeQualifierDefault
,
beside TYPE_ARGUMENT
.
The latter one should have the following effect: if a default qualifier is determined
to be applied to some top-level type (using the same logic as for @TypeQualifierDefault
)
and the set of applicability kinds contain TYPE_ARGUMENT
then this qualifier should also be applied
to all of it's type arguments (recursively).
We suggest to introduce a separate annotation meta.ApplyByDefault
with vararg-parameter
of type ApplicabilityKind
:
@Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class ApplyByDefault(val qualifier: KClass<*>, vararg val elements: ApplicabilityKind)
Basically, it should work just the same as @TypeQualifierDefault
, e.g. it might be used like:
@ApplyByDefault(MyNullable::class, ApplicabilityKind.PARAMETER)
annotation class MyAllParametersAreNullableByDefault
@ApplyByDefault(MyNonnull::class, ApplicabilityKind.PARAMETER)
annotation class MyAllParametersAreNonNullByDefault
@ApplyByDefault(MyNullable::class, ApplicabilityKind.PARAMETER)
annotation class MyAllParametersAreNullableByDefault
@ApplyByDefault(
MyNonnull::class,
ApplicabilityKind.RETURN_TYPE, ApplicabilityKind.VALUE_PARAMETER,
ApplicabilityKind.FIELD, ApplicabilityKind.TYPE_ARGUMENT
)
annotation class MyApiNonNullByDefault
NB: When module-info
classes are annotated with a default qualifiers it should work just like being applied to all
classes in the modules.
To simplify its semantics, we suggest to restrict applicability of @UnderMigration
only to qualifier aliases (i.e. to annotations that are meta-annotated with meta.Alias
).
Thus, when being applied to a default qualifier @UnderMigration
should be effectively ignored.
There is already an artifact called kotlin-annotations-jvm that might be the best candidate where the new meta annotations may be placed.
Probably, the annotations that are already there should be moved to a different packages:
kotlin.annotations.jvm.UnderMigration
,kotlin.annotations.jvm.MigrationStatus
->kotlin.annotations.jvm.meta
kotlin.annotations.jvm.Mutable
,kotlin.annotations.jvm.ReadOnly
->kotlin.annotations.jvm.collections
- Should aliasing JSR-305 qualifiers like
javax.annotation.Nonnull
be allowed? - What is the best name for
ApplicabilityKind
enum class? Would it be better to place it inside theApplyByDefault
annotation class (if it will be there) - What bytecode version should all those annotations have?
On one side, we'd like to have compatibility with 1.6, on the other, we'd like them to have
ElementType.TYPE_USE
among their targets - Do we need to add built-in default qualifiers (like
@AllParametersAreNotNullByDefault
or@NotNullAPI
)?