14

In Java I have the possibility to "implement" annotations.

Sample Java annotation:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface JavaClassAnno {
  String[] value();
}

Sample Java "implementation":

class MyAnnotationLiteral 
                  extends AnnotationLiteral<JavaClassAnno> 
                  implements JavaClassAnno { // <--- works in Java
  private String value;

  public MyAnnotationLiteral(String value) {
    this.value = value;
  }
  @Override
  public String[] value() {
    return new String[] { value };
  }
}

Trying to port that to Kotlin doesn't work as it says that the annotation is final and therefore can not be inherited, i.e. the following will not work:

class MyAnnotationLiteral(private val internalValue: String) 
                 : AnnotationLiteral<JavaClassAnno>(), 
                   JavaClassAnno { // <--- doesn't work in Kotlin (annotation can not be inherited)
  override fun value(): Array<String> {
    return arrayOf(internalValue)
  }
}

How do you "implement/extend" annotations the Kotlin way? Could not find any reason why Kotlin differs in that regard to Java. Any hint how to solve that problem or any sources that tell why it is that way are welcome.

The following question contains a use case for this constellation: Dynamically fire CDI event with qualifier with members. Basically you require something like this to narrow down which qualifier should trigger based on its members.

Note that this would also apply to a Kotlin annotation as well as it seems that a Kotlin annotation can not be open and therefore not be implemented/extended too.

What I found so far is rather mentioning @Inherited as a problem:

But I did not find any reason why the annotation is not implementable/inheritable as it is in Java.

I also asked this question now here: https://discuss.kotlinlang.org/t/implement-inherit-extend-annotation-in-kotlin/8916

Update: Finally I found something regarding this design decision, namely the following issue (while I was opening my own issue for it): Annotations inheritance. Either prohibit or implement correctly. As it seems the decision was to "prohibit" it, even though there are no (visible?) comments, discussions or other sources about that decision.

Added the following issue: https://youtrack.jetbrains.com/issue/KT-25947

11
  • 3
    Huh. I've never seen a class try to implements an annotation, and I didn't realize that it was even possible. You nearly always apply the annotation to the class. Commented Jul 31, 2018 at 8:37
  • 1
    At least in Java I saw it already several times. One such example is when you try to select an instance in CDI, where you usually use AnnotationLiterals, which are basically "implementations" of annotations. However you may only require such an implementation if you need to supply values or other specific attributes your annotation has. Commented Jul 31, 2018 at 8:40
  • 1
    Can you point me to actual code that does that? Using an annotation as a qualifier usually doesn't involve implementing it. Commented Jul 31, 2018 at 8:42
  • 2
    Here is an example question. Basically you require something like this to narrow down which qualifier should trigger based on its members. Commented Jul 31, 2018 at 8:48
  • 2
    The annotation is still written in Java, but the same would apply to a Kotlin annotation as well (you can't open it). Commented Jul 31, 2018 at 8:55

1 Answer 1

5

As of Kotlin 1.3, this case is not supported. To create custom instances of annotations one has to resort to Java for now. One of the reasons for this design decision is that making annotations interfaces is too JVM-specific and wouldn't map well to other platforms.

Sign up to request clarification or add additional context in comments.

4 Comments

While I understand that decision (and AnnotationLiteral is definitely a rather special case), I wondered also about things like @JvmName already ;-) Are there plans to have something like Kotlin-only on the JVM (without needing @Jvm-annotations)? So maybe like: I am 100% sure (and know what I am doing) and just want to call Kotlin and Java code, but do not want to be able to call Kotlin code from Java (or I wouldn't mind if code called from Java would look ugly because method names might be generated)?
@Roland I can't see how your question is related to the topic here. Also, I can't see why you need @JvmName at all if you don't care about Java API. Let's discuss it elsewhere
Sorry.. I just jumped from annotations to "too JVM-specific" and reminded myself about name clashes requiring @JvmName and wrote what came to my mind ;-) you are right, that's not really related... sure, where do we want to continue?
@Roland I think it's a good discussion for our public Slack or forum

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.