Thursday, February 10, 2011

Metadata Annotations

Metadata annotations provide a powerful way to extend the capabilities of a programming language and the language runtime. These annotations can be directives that request the runtime to perform certain additional tasks, provide extra information about an item or extend the abilities of a type. Metadata annotations are common in a number of programming environments including Microsoft's COM and the Linux kernel.
C# attributes provide a way to add annotations (i.e. metadata) to a module, type, method, parameter or member variable. Below are descriptions of a few attributes that are intrinsic to .NET and how they are used to extend the capabilities of the C#.
  1. [MethodImpl(MethodImplOptions.Synchronized)]: is used to specify that a access to a method by multiple threads is protected by a lock to prevent concurrent access to the method and is similar to the synchronized in Java.

  2. [Serializable]: is used to mark a class as serializable and is similar to a Java class implementing the Serializable interface.

  3. [FlagsAttribute]: is used to specify that an enum should support bitwise operations. This is particularly important for enumerations where the target can have multiple values.
    C# Code
    //declaration of bit field enumeration
    [Flags]
    enum ProgrammingLanguages{
    C = 1,
    Lisp = 2,
    Basic = 4,
    All = C | Lisp | Basic
    }

    aProgrammer.KnownLanguages = ProgrammingLanguages.Lisp; //set known languages ="Lisp"
    aProgrammer.KnownLanguages |= ProgrammingLanguages.C; //set known languages ="Lisp C"
    aProgrammer.KnownLanguages &= ~ProgrammingLanguages.Lisp; //set known languages ="C"

    if((aProgrammer.KnownLanguages & ProgrammingLanguages.C) > 0){ //if programmer knows C
    //.. do something
    }
  4. [WebMethod]: is used in combination with ASP.NET to specify that a method should be available over the web as a web service automatically. Doing the same in Java involves configuring JAXP, UDDI, and J2EE as well as have to create an Enterprise Java Bean which involves at least two interfaces and one implementation class plus setting up the deployment descriptor. For more information on webservices in C#, examine the Your First C# Web Service page on CodeProject.
It is possible to access the attributes of a module, class, method or field via reflection. This is particularly useful for seeing if a class supports certain behavior at runtime or for extracting metadata about a class for usage by others. Developers can create their own custom attributes by subclassing the System.Attribute class. What follows is an example of using an attribute to provide information about the author of a class then using reflection to access that information.
C# Code
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Class)]
public class AuthorInfoAttribute: System.Attribute{

string author;
string email;
string version;


public AuthorInfoAttribute(string author, string email){

this.author = author;
this.email = email;

}


public string Version{


get{
return version;
}

set{
version = value;
}

}


public string Email{


get{
return email;
}

}

public string Author{


get{
return author;
}

}

}



[AuthorInfo("Dare Obasanjo", "kpako@yahoo.com", Version="1.0")]
class HelloWorld{

}



class AttributeTest{

public static void Main(string[] args){

/* Get Type object of HelloWorld class */
Type t = typeof(HelloWorld);

Console.WriteLine("Author Information for " + t);
Console.WriteLine("=================================");

foreach(AuthorInfoAttribute att in t.GetCustomAttributes(typeof(AuthorInfoAttribute), false)){

Console.WriteLine("Author: " + att.Author);
Console.WriteLine("Email: " + att.Email);
Console.WriteLine("Version: " + att.Version);

}//foreach

}//Main

}
Java annotations provide a way to add annotations (i.e. metadata) to an package, type, method, parameter, member or local variable. There are only three built-in annotations provided in the Java language which are listed below.
  1. @Override: is used to specify that a method is intended to override a method in a base class. If the annotated method does not override a method in the base class then an error is issued during compilation.

  2. @Deprecated: is used to indicate that a particular method has been deprecated. If the annotated method is used then a warning is issued during compilation.

  3. @SuppressWarnings: is used to prevent particular warnings from being issued by the compiler. This annotation optionally takes the name of the specific warning to suppress as an argument.
As in C# it is possible to access the annotations on a module, class, method or field via reflection. However a key difference between C# attributes and Java annotations is that one can create meta-annotations (i.e. annotations on annotations) in Java but can not do the same in C#. Developers can create their own custom annotations by creating an annotation type which is similar to an interface except that the keyword @interface is used to define it. What follows is an example of using an attribute to provide information about the author of a class then using reflection to access that information.
Java Code
import java.lang.annotation.*;
import java.lang.reflect.*;

@Documented //we want the annotation to show up in the Javadocs
@Retention(RetentionPolicy.RUNTIME) //we want annotation metadata to be exposed at runtime
@interface AuthorInfo{
String author();
String email();
String version() default "1.0";
}

@AuthorInfo(author="Dare Obasanjo", email="kpako@yahoo.com")
class HelloWorld{

}

public class Test{

public static void main(String[] args) throws Exception{

/* Get Class object of HelloWorld class */
Class c = Class.forName("HelloWorld");
AuthorInfo a = (AuthorInfo) c.getAnnotation(AuthorInfo.class);

System.out.println("Author Information for " + c);
System.out.println("=======================================");
System.out.println("Author: " + a.author());
System.out.println("Email: " + a.email());
System.out.println("Version: " + a.version());

}
}

No comments:

Post a Comment