Tom
Tom

Reputation: 6332

How to access scala annotation in scala code

I have defined a simple scala annoation and use it to annotate my case class Person:

package com.my

import  scala.annotation.StaticAnnotation

@scala.annotation.meta.field
class Description(value: String) extends StaticAnnotation{

}

Then I use it in my Person class:

package com.my

import scala.beans.BeanProperty

case class Person(

                   @Description(value = "name00")
                   name: String,

                   @Description(value = "age00")
                   age: Int,

                   @BeanProperty
                   xyz: String = "xyz"
                 )

object Person {
  def main(args: Array[String]): Unit = {
    val p = Person("abc", 21)
    classOf[Person].getDeclaredFields.foreach {
      field =>
        field.setAccessible(true)
        val name = field.getName
        val value = field.get(p)
        //annotations always return empty array
        val annotations = field.getDeclaredAnnotations
        annotations.foreach {
          annotation =>
            val tpe = annotation.annotationType()
            println(tpe)
        }
        println(s"name is $name, value is: $value")
    }
  }
}

In the main method of Person object, the annotations array is always empty, I would like to ask how to get the annoation information defined on the field.

Upvotes: 1

Views: 1176

Answers (1)

Dmytro Mitin
Dmytro Mitin

Reputation: 51658

Firstly, annotations written in Scala are accessible in sources (if the annotations extend scala.annotation.Annotation) and class files (if if the annotations extend scala.annotation.StaticAnnotation). In order to be accessible at runtime the annotations must be written in Java

import java.lang.annotation.*;

@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Description {
    String value();
}

How to use Scala annotations in Java code

Why annotations written in Scala are not accessible at runtime?

https://www.reddit.com/r/scala/comments/81qzs2/how_to_write_annotations_in_scala/

Alternatively you can use the original @Description (written in Scala and extending StaticAnnotation) but then you have to access it at runtime via Scala reflection rather than Java reflection.

Secondly, you misuse meta-annotations (@scala.annotation.meta.field). They should annotate not the definition of @Description but its applications.

import scala.annotation.meta.field

case class Person(
                   @(Description @field)(value = "name00")
                   name: String,

                   @(Description @field)(value = "age00")
                   age: Int,

                   @BeanProperty
                   xyz: String = "xyz"
                 )

Annotating case class parameters

How can I reflect on a field annotation (Java) in a Scala program?

Calling a method from Annotation using reflection

Output:

interface Description // appears
name is name, value is: abc
interface Description // appears
name is age, value is: 21
name is xyz, value is: xyz

With Scala reflection you can do

import scala.annotation.StaticAnnotation
import scala.beans.BeanProperty
import scala.annotation.meta.field
import scala.reflect.runtime.universe._

class Description(value: String) extends StaticAnnotation

case class Person(
                   @(Description @field)(value = "name00")
                   name: String,

                   @(Description @field)(value = "age00")
                   age: Int,

                   @BeanProperty
                   xyz: String = "xyz"
                 )

def main(args: Array[String]): Unit = {
  val p = Person("abc", 21)
  typeOf[Person].decls
    .collect { case t: TermSymbol if t.isVal => t.annotations }
    .foreach(println)
}

//List(Description @scala.annotation.meta.field("name00"))
//List(Description @scala.annotation.meta.field("age00"))
//List(scala.beans.BeanProperty)

Upvotes: 2

Related Questions