Saturday, December 8, 2012

Java Custom Annotations - Intuitive view


Java Custom Annotations - Intuitive understanding


Annotation, in simple terms, is a description of something, but not all descriptions could be considered as valid annotations in programming world. Simple Java comments couldn't be considered as an annotation, but a Javadoc could be. Formally, annotation is meta-data of some data. Meta-data is a type of data which could be understood by compiler or run-time like JVM, but shall be treated differently than normal data.

For instance, Annotations in a java class is a means to provide some extra information about that class. But, why is it useful? You could have used some of the compile-time annotations in your code, which provide some hints to the compiler like @ SuppressWarnings, @Deprecated, etc. Annotations are much more powerful which could make certain great stuff possible. Let us start with an example and understand the power of Annotations intuitively.


Let us think of a simple client-server protocol which exchanges messages through TCP Layer. And we define Messaging protocol as follows:

command + "END" + data

command -> defines the action to be performed
"END" -> delimiter for command message
data -> data on which action shall be performed

For example,
"echoENDHello World" shall be handled by the Server to return the data "Hello World" as echo is the command which is not supposed to do any operation on the data.

Now let us think of the server's implementation for this. All messages shall be received by a socket and sent to a message processor object for processing. In the processor, parsing may happen and according to the command, a right handler could be selected to process further.


The complete example is uploaded in the GIT. https://github.com/karthikmit/AnnotationsDemo

And this is for demo purpose and expect some TODOs here and there :)


For the Echo command, we may define a EchoHandler class which extends Handler interface. We may define a handler factory which returns the EchoHandler object, given the command parameter, echo. This design is almost loosely coupled as adding a new command, needs a new handler class to be implemented and some changes in Handler Factory and no changes needed in other components. Wait, what is the information being held by this Handler factory? Is that dependency really needed? Yes, because a class derived from Handler interface isn't capable of informing its own purpose to other components. There are several ways by which this information could be injected into the class, think of a final string which says which command it is capable of handling.

Annotations is a non-intrusive and programmatic way by which this sort of extra information about the class can be clearly expressed. Non-intrusive means the annotations don't do any harm on its own to the host class. If we could annotate the new controller with the new command, message processor could utilize this annotation during its handler discovery phase. A perfect de-coupling is possible with annotations. Let us get into some details of annotations.

Annotation is actually an interface and Handler annotation could be defined as follows.



@ in front of interface keyword, can be understood as AT, Annotation Type. Apart from this, there is no distinction between normal interface and Annotation definition.
Target and Retention are the meta annotations which "describe" annotations. To make this example complete, Target says this annotation should be applied at Class level;  BTW, Method and Field level annotations are also possible. Retention says annotation should be available at RunTime. We need this annotation at run-time for message processor object to discover the command handlers.

Given annotation is an interface, we need to instantiate somewhere, right. Let us check the Echo handler code to understand this.



Like a Java modifier, annotation precedes the definition. In the above snippet, we annotate the EchoMessageHandler with Handler and makes its value to return "echo". This could be thought of as instantiation of Handler annotation interface.

I need to digress a bit; Check the Override annotation in the above snippet, which is actually annotating "handle" method. This annotation says that this method should be the parent interface method and is getting overridden. If that is not so, compiler would throw an error. Since Override annotation is Compile-time stuff, Run-time doesn't have any idea about this annotation.

Handler discovery of MessageProcessor class can be defined as follows:



Every Class object of type and Method object of class methods has a method getAnnotations which gives an array of annotations. This could be utilized for Handler discovery in this example.

1 comment:

  1. simple yet informative write-up. thanks karthik.
    1) so the dependency from the HandlerFactory is shifted to the "commandHandlerMap" in MessageProcessor but the advantage being this happens in run-time so the portion of code is generic.

    2) Dependency Injection is achieved via the annotation

    Pls. clarify

    ReplyDelete