zondag 7 april 2013

Annotations

Introduction

I have been working with Annotations for a while now. There are three different ways to read the information coming from these annotations. All three of them are inflicted through the Reflection API.
this.getclass.getDeclaredFields().getDeclaredAnnotations();

An annotation might look something like this:

@Retention(RetentionPolicy.RUNTIME) //you need to have this. Otherwise it does not work.
public @interface Thest {
    String test(); // required
    String test2() default =""; //optional
}

An annotation can handle only basic types like String, int double etc. It also can deal with Enum types.


1. Bad design:

This is the first way I found on the internet how too deal with annoations. Personally I think it is the less elegant of the three I know:

if(@test instanceof Test){
   test = (@Test)test;
}
String test = test. test();

This method is not elegant because If you have a good design you know what Annotation is requested. So you dont have too test the instance.

2.  Getting rid of the casts

Also casting is not necassary.  If you look at what Java provides you with:

Test test =field.getAnnotation(Test.class);

This still requires a good design to get rid of the isInstance of part.

3. For the fast and furious:

Lets be honest the best thing we can do as programmers is design this baby and get rid of all the trouble that can excist. But then there is reality (Which comes with managers and deadlines) These are the moments where we need a solution in the middle:

In this example we have a bit more complex situation:

@Type (field = Field.type
@Test (value = "test")

The point I am trying to make is that if you have more then one annotation, that could be per annotated field or just in general, you might find yourself in time shortage (what is new?) and need a  solution that doesnt require time too design but still gives you the oppurtunity too read all you need.


private void translateAnnotations(Annotation annotation){
String[] values = annotation.toString().split(",");
for (int i = 0; i < values.length; i++) {
String value = values[i];
if(value.startsWith(AT)){
String[] tempValue = value.split("\\.");
int arrayLength = tempValue.length-1;
value = tempValue[arrayLength];
}
createTestElements(value);
}

}

private void createTestElements(String testElement){
String part = null;
if(Character.isUpperCase(TestElement.charAt(0))){
String[] testElementParts = testElement.split("\\(");
part = testElementParts[0];
}
testElement = testElement.substring(testElement.indexOf('(') + 1, testlement.length());
String[] valueParts = testElement.split("=");
if(valueParts.length > 1){
if(testElement.endsWith(")")){
testElement = testElement.substring(0, testElement.length()-1);
}
String[] testElements = testElement.split("=");
if(testElements[0].trim().equals(TEST)){
testBean.setQuery(testElements[1]);
}
else if(testElements[0].trim().equals(ATTRIBUTE_NAME)){
testBean.setTest(AT + estElements[1]);
}
else if(testElements[0].trim().equals(ELEMENT_NAME)){
testBean.setElementName(testElements[1]);
}else if(testElements[0].trim().equals(PART)){
testBean.setType(testElements[1]);
if(part != null){
testBean.setPart(part);
}
}else if(testElements[0].trim().equals(TEST_SUB_SECTION)){
testDataBean.setTestSubSection(testElements[1]);
}
}
}

Conclusion:

The best thing you can do with annotations, design the thing so that you know who is visiting. But in some cases delivering is the main thing they put on your mind and you need something in the middle.
For design patterns have a look at: http://en.wikipedia.org/wiki/Software_design_pattern
And in this perticulair case I would be interested in the Visitor pattern.

Have Fun!