I'm trying to use a Java library (JOhm) with Scala and noticed it fails when the lib tries to read the annotations on the fields of my Scala classes with something like field.isAnnotationPresent(Id.class)
.
The annotations are defined in Java with:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Id {
}
So they should be available on runtime. However, if I try:
scala> import redis.clients.johm._
import redis.clients.johm._
scala> class myClass(@Id var id: java.lang.Long)
defined class myClass
scala> new myClass(id = null)
res0: myClass = myClass@5157cfbc
scala> res0.getClass.getDeclaredFields
res1: Array[java.lang.reflect.Field] = Array(private java.lang.Long myClass.id)
scala> res0.getClass.getDeclaredFields.map(_.getAnnotations)
res2: Array[Array[java.lang.annotation.Annotation]] = Array(Array())
Then I manage to get the fields (thanks to StackOverflow users…) but I still cannot access the annotations. What did I do wrong?
Thanks to 'soc' for reference provided, there is a definitive answer: "By default, annotations on (val-, var- or plain) constructor parameters end up on the parameter...".
The annotation in question is defined for FIELD elements with run-time retention, while it's being applied to a scala constructor argument (PARAMETER).
I had the same situation recently trying to use a JAXB FIELD level @XmlElement annotation on a scala constructor "var" parameter - didn't work for me either.
I solved my JAXB issue by defining a distinct field in the class, and initializing it from the constructor's parameter list (eliminating the 'val/var' keyword). In your case that might look like:
The reference suggests two other alternatives:
Changing(adding) element type of the annotation to (include) PARAMETER; this is only viable if the source is available.
Use the target package in 2.9.2, which has been renamed to meta package for 2.10, to re-classify (re-target) the annotation to an underlying field (or other option).