- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
A Tour of Scala: Annotations
Created by admin on 2008-07-05.
Updated: 2010-08-31, 15:25
Annotations associate meta-information with definitions.
A simple annotation clause has the form @C
or @C(a1, .., an)
. Here, C
is a constructor of a class C
, which must conform to the class scala.Annotation
. All given constructor arguments a1, .., an
must be constant expressions (i.e., expressions on numeral literals, strings, class literals, Java enumerations and one-dimensional arrays of them).
An annotation clause applies to the first definition or declaration following it. More than one annotation clause may precede a definition and declaration. The order in which these clauses are given does not matter.
The meaning of annotation clauses is implementation-dependent. On the Java platform, the following Scala annotations have a standard meaning.
Scala | Java | |
---|---|---|
scala.SerialVersionUID | serialVersionUID (field) | |
scala.cloneable | java.lang.Cloneable | |
scala.deprecated | java.lang.Deprecated | |
scala.inline (since 2.6.0) | no equivalent | |
scala.native (since 2.6.0) | native (keyword) | |
scala.remote | java.rmi.Remote | |
scala.serializable | java.io.Serializable | |
scala.throws | throws (keyword) | |
scala.transient | transient (keyword) | |
scala.unchecked (since 2.4.0) | no equivalent | |
scala.volatile | volatile (keyword) | |
scala.reflect.BeanProperty | Design pattern |
In the following example we add the throws
annotation to the definition of the method read
in order to catch the thrown exception in the Java main program.
A Java compiler checks that a program contains handlers for checked exceptions by analyzing which checked exceptions can result from execution of a method or constructor. For each checked exception which is a possible result, the throws clause for the method or constructor must mention the class of that exception or one of the superclasses of the class of that exception.
Since Scala has no checked exceptions, Scala methods must be annotated with one or more throws
annotations such that Java code can catch exceptions thrown by a Scala method.
package examples import java.io._ class Reader(fname: String) { private val in = new BufferedReader(new FileReader(fname)) @throws(classOf[IOException]) def read() = in.read() }
The following Java program prints out the contents of the file whose name is passed as the first argument to the main
method.
package test; import examples.Reader; // Scala class !! public class AnnotaTest { public static void main(String[] args) { try { Reader in = new Reader(args[0]); int c; while ((c = in.read()) != -1) { System.out.print((char) c); } } catch (java.io.Exception e) { System.out.println(e.getMessage()); } } }
Commenting out the throws
annotation in the class Reader
produces the following error message when compiling the Java main program:
Main.java:11: exception java.io.IOException is never thrown in body of corresponding try statement } catch (java.io.IOException e) { ^ 1 error
Java annotations
Note: Make sure you use the -target:jvm-1.5
option with Java annotations.
Java 1.5 introduced user-defined metadata in the form of annotations. A key feature of annotations is that they rely on specifying name-value pairs to initialize their elements. For instance, if we need an annotation to track the source of some class we might define it as
@interface Source { public String URL(); public String mail(); }
And then apply it as follows
@Source(URL = "http://coders.com/", mail = "support [at] coders [dot] com") public class MyClass extends HisClass ...
An annotation application in Scala looks like a constructor invocation, for instantiating a Java annotation one has to use named arguments:
@Source(URL = "http://coders.com/", mail = "support [at] coders [dot] com") class MyScalaClass ...
This syntax is quite tedious if the annotation contains only one element (without default value) so, by convention, if the name is specified as value
it can be applied in Java using a constructor-like syntax:
@interface SourceURL { public String value(); public String mail() default ""; }
And then apply it as follows
@SourceURL("http://coders.com/") public class MyClass extends HisClass ...
In this case, Scala provides the same possibility
@SourceURL("http://coders.com/") class MyScalaClass ...
The mail
element was specified with a default value so we need not explicitly provide a value for it. However, if we need to do it we can not mix-and-match the two styles in Java:
@SourceURL(value = "http://coders.com/", mail = "support [at] coders [dot] com") public class MyClass extends HisClass ...
Scala provides more flexibility in this respect
@SourceURL("http://coders.com/", mail = "support [at] coders [dot] com") class MyScalaClass ...
This extended syntax is consistent with .NET's annotations and can accomodate their full capabilites.