Scala Annotations are metadata or extra information added to the program source code. Like comments, annotations can be attached to a variable, method, expression or any other program element.
Annotations are allowed on any kind of definition or declaration including vars, vals, classes, objects, traits, defs and types.
The syntax for declaring an annotation can be of the form;
1 2 3 |
@annot(exp_{1}, exp_{2}, ...) {val name_{1}=const_{1}, ..., val name_{n}=const_{n}} |
The “annot” specifies the class of the annotation and all annotations must include this. Some of the annotations might not need any arguments and hence the parentheses can be excluded or an empty () can be used.
The precise form of the arguments given to the annotation depends on the annotation class in particular. Most annotation processors allow immediate constants such as “Hi”, 678 etc. Keyword “this” can be used to refer to other variables in the scope.
The “name=const” are available for more complicated annotations having optional arguments. These arguments are optional, and they can be specified in any order. The right hand side value after equals sign is recommended to be a constant.
Scala Standard Annotations
Scala has several standard annotations. They are;
scala.SerialVersionUID → This annotation specifies the static SerialVersionUID field of a serializable class.
scala.deprecated → This annotations tells that the definition is removed.
scala.volatile → This annotations allows programmers to use mutable state in concurrent programs.
scala.transient → This annotation marks a field to be non-persistent.
scala.throws → This annotation specifies the exceptions thrown by a method.
scala.cloneable → This annotation designates the class to which it is applied as cloneable
scala.native → This annotation is a marker for native methods.
scala.inline → This annotation on methods requests that the compiler should try hard to inline the annotated method.
scala.remote → This annotation designates the class to which it is applied as remotable.
scala.serializable → This annotation designates the class to which it is applied as serializable
scala.unchecked → This annotation gets applied to a selector in a match expression. If present, exhaustiveness warnings for that expression will be suppressed.
scala.reflectBeanProperty → This annotation adds getter and setter methods following the JavaBean convention when attached to a field.
Let’s look at some of the annotations with examples.
Deprecation Annotation
There arises a need to write a class or a method that is not needed for later use. Deprecation allows us to add a notification in the method or a class that we don’t want others to use, but we can’t remove for backward compatibility. The method or class can be marked as @deprecated so that when others try to use this a deprecation warning is shown.
For example create a Scala object as below.
deprecated.scala
1 2 3 4 5 6 7 8 9 10 11 12 |
package com.annotations import scala.deprecated; object Deprecation1 { @deprecated def printMessage() = { println("This method is deprecated") } def main(args: Array[String]) { printMessage() } } |
The method printMessage is marked as deprecated. The Scala compiler will emit the deprecation warnings whenever Scala code accesses printMessage method in the main as shown in the below image.
Volatile fields
Sometimes programmers want to use mutable state in the concurrent programs. The @volatile
annotation helps in such cases and informs the compiler that the variable will be used by multiple threads. The @volatile keyword gives different guarantees on different platforms such as on the Java platform, however, you get the same behavior as if you wrote the field in Java code and marked it with the Java volatile modifier.
Binary Serialization
Serialization framework converts objects into stream of bytes and vice versa which would be useful while saving objects to the disk or transferring them over a network. Scala does not have its own serialization framework and hence an underlying framework should be used. The @serializable
annotation indicates whether a class is serializable. By default the class is considered as not serializable and hence the @serializable annotation is added.
The @SerialVersionUID
deals with the serializable classes that changes with time. The serial number can be attached to current version as @SerialVersionUID(678)
where 678 is the serial id.
Scala provides @transient
annotation for fields. If the field is marked as @transient, then the framework should not save the field even when the surrounding object is serialized. When the object is loaded, the field will be restored to the default value for the type of the field annotated as @transient.
Automatic getter and setter methods
Scala provides the @scala.reflect.BeanProperty
annotation that adds this annotation to a field and the compiler automatically generate getter and setter methods for the field.
For example – If you annotate a field named id, the getter method will be named getId
and the setter method will be named setId
. The getter and setter methods are available only after the compilation pass completes. Scala code fields can be accessed directly. This feature is intended to support frameworks that expect regular getter and setter methods and do not compile the framework, code that used it at the same time.
For instance Open the Scala IDE and create the scala class as;
Car.scala
1 2 3 4 5 6 7 8 9 10 |
package scala.annotations.car import scala.beans.BeanProperty class Car { @BeanProperty var cname = "Alto" @BeanProperty var cno = 67 } |
We are using the @BeanProperty annotation which generates getter setter methods for properties cname and cno.
Now create a java program and use the scala Car class created as
Bean.java
1 2 3 4 5 6 7 8 9 10 11 |
package com.annotations; import scala.annotations.car.*; public class Bean { public static void main(String[] args){ Car c = new Car(); System.out.println("Car Name:" +c.getCname()); System.out.println("Car Number: "+c.getCno()); } } |
The getter methods for cname and cno are generated by the scala @BeanProperty methods that can be used in Java programs as shown in above class code.
Unchecked
The @unchecked annotation is interpreted by the compiler during pattern matches. It tells the compiler not to worry if the match expression seems to leave out some cases.
That’s all for annotations in Scala programming, you can explore other annotations listed above yourself.