1

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.

5
  • 1
    Why do you need those annotations? Maybe you can solve your original problem in a simpler / cleaner way. Commented Aug 31, 2020 at 4:53
  • 3
    Scala annotations are different than Java annotations, you use use Scala Reflection API to access them. Commented Aug 31, 2020 at 8:33
  • @LuisMiguelMejíaSuárez. I just use this simple code to illustrate my problem here, the key point is that I want to use scala annotation, thanks. Commented Aug 31, 2020 at 11:22
  • 1
    @Tom Why is it important to use Scala annotation? Can you use Java annotation? (Anyway you use Java reflection, not Scala reflection.) Commented Aug 31, 2020 at 11:31
  • @Tom Anyway if it's important that @Description is Scala annotation see update of my answer with Scala reflection. Commented Aug 31, 2020 at 13:32

1 Answer 1

2

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)
Sign up to request clarification or add additional context in comments.

Comments

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.