Showing posts with label Annotation. Show all posts
Showing posts with label Annotation. Show all posts

Thursday, October 19, 2017

Java Annotation, Reflection and Inheritance

Annotation

Annotation is most commonly used to store extra information in classes that could be used at runtime by frameworks.

An annotation is defined as meta-data type. attributes could be added to store specific values when the annotation is used.

Reflection

Frameworks use the Java reflection to retrieve annotations.

Inheritance

Annotation Subclass

It is not possible to extend an annotation to create a annotation type hierarchy. However a new annotation could be created to substitute an annotation with specific attribute values when it is used frequently. Or a new annotation could be used to represent multiple annotations if they are frequently used together.

such as:

@Category(value="Food")
public @interface FoodCategory {}

@Action1
@Action2
@Action3
public @interface ActionGroup1 {}


Annotation Type Declaration Inheritance

If the @Inherited annotation is used, the Annotation declaration is inherited in class hierarchy only. The annotation declaration on an interface is not inherited.

However, the Annotations declared on interfaces are able to be used by their sub types by using reflection to search its type hierarchy. If the interfaces are searched, it is going to be a tree search!

Here are some tests that demo the usages of get annotations in type hierarchies through reflection:



@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Inherited
public @interface MyAnnotation {
       String name();
       String value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@MyAnnotation(name = "usage", value = "extends")
public @interface MyAnnotationExt {
       String name();
       String value();
}

public class AnnotationUsages {

       @MyAnnotation(name = "name1", value = "value1")
       public void getAnnotation() {
             try {
                    Class<? extends AnnotationUsages> cls = this.getClass();
                    Method method = cls.getMethod("getAnnotation");
                    MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
                    System.out.println(myAnnotation);
             } catch (SecurityException | NoSuchMethodException e) {
                    e.printStackTrace();
             }
       }

       @MyAnnotationExt(name = "name2", value = "value2")
       public void getAnnotationOfAnnotation() {
             try {
                    Class<? extends AnnotationUsages> cls = this.getClass();
                    Method mth = cls.getMethod("getAnnotationOfAnnotation");
                    Annotation[] annotations = mth.getAnnotations();
                    for (Annotation annotation : annotations) {
                           System.out.println(annotation.toString());
                    }
                    MyAnnotationExt myAnnotationExt = mth.getAnnotation(MyAnnotationExt.class);
                    annotations = myAnnotationExt.annotationType().getAnnotations();
                    for (Annotation annotation : annotations) {
                           System.out.println(annotation.toString());
                    }
             } catch (SecurityException | NoSuchMethodException e) {
                    e.printStackTrace();
             }
       }

       // Annotations over annotation

       @Test
       public void testMethodAnnotations() {
             AnnotationUsages usages = new AnnotationUsages();
             usages.getAnnotation();
             usages.getAnnotationOfAnnotation();
       }

       // Annotations over type hierarchy

       @Test
       public void testTypeAnnotations() {
             MyClass1 cls1 = new MyClass1();
             cls1.getTypeAnnotation();
             MyClass2 cls2 = new MyClass2();
             cls2.getTypeAnnotation();
             MyClass3 cls3 = new MyClass3();
             cls3.getTypeAnnotation();
             MyInterface myInterfaceInstance = new MyClass3();
             System.out.println("===MyInterface===");
             try {
                    Class<?> myInterface = myInterfaceInstance.getClass().getInterfaces()[0];
                    Annotation[] annotations = myInterface.getAnnotations();
                    for (Annotation annotation : annotations) {
                           System.out.println(annotation.toString());
                    }
             } catch (SecurityException e) {
                    e.printStackTrace();
             }
       }

       @MyAnnotation(name = "name1", value = "value1")
       @MyAnnotationExt(name = "name2", value = "value2")
       interface MyInterface {
             public void getTypeAnnotation();
       }

       @MyAnnotation(name = "name10", value = "value10")
       @MyAnnotationExt(name = "name20", value = "value20")
       public static class MyClass1 {
             public void getTypeAnnotation() {
                    try {
                           System.out.println("===MyClass1===");
                           Class<? extends MyClass1> cls = this.getClass();
                           Annotation[] annotations = cls.getAnnotations();
                           for (Annotation annotation : annotations) {
                                 System.out.println(annotation.toString());
                           }
                    } catch (SecurityException e) {
                           e.printStackTrace();
                    }
             }
       }

       public static class MyClass2 extends MyClass1 {
             @Override
             public void getTypeAnnotation() {
                    System.out.println("===MyClass2===");
                    try {
                           Class<? extends MyClass2> cls = this.getClass();
                           Annotation[] annotations = cls.getAnnotations();
                           for (Annotation annotation : annotations) {
                                 System.out.println(annotation.toString());
                           }
                    } catch (SecurityException e) {
                           e.printStackTrace();
                    }
             }
       }

       public static class MyClass3 implements MyInterface {
             @Override
             public void getTypeAnnotation() {
                    System.out.println("===MyClass3===");
                    try {
                           Class<? extends MyClass3> cls = this.getClass();
                           Annotation[] annotations = cls.getAnnotations();
                           for (Annotation annotation : annotations) {
                                 System.out.println(annotation.toString());
                           }
                    } catch (SecurityException e) {
                           e.printStackTrace();
                    }
             }
       }
}





 The results:


@com.americanexpress.ssae.sample.annotation.MyAnnotation(name=name1, value=value1)
@com.americanexpress.ssae.sample.annotation.MyAnnotationExt(name=name2, value=value2)
@java.lang.annotation.Retention(value=RUNTIME)
@java.lang.annotation.Target(value=[TYPE, METHOD, PARAMETER, FIELD, ANNOTATION_TYPE])
@com.americanexpress.ssae.sample.annotation.MyAnnotation(name=usage, value=extends)

===MyClass1===
@com.americanexpress.ssae.sample.annotation.MyAnnotation(name=name10, value=value10)
@com.americanexpress.ssae.sample.annotation.MyAnnotationExt(name=name20, value=value20)
===MyClass2===
@com.americanexpress.ssae.sample.annotation.MyAnnotation(name=name10, value=value10)
===MyClass3===
===MyInterface===
@com.americanexpress.ssae.sample.annotation.MyAnnotation(name=name1, value=value1)
@com.americanexpress.ssae.sample.annotation.MyAnnotationExt(name=name2, value=value2)

Sunday, May 21, 2017

Springframework Async annotation and ThreadExcutor's AbortPolicy

The Springframework has @Async annotation.

it simplifies the asynchronous method execution and hides the implementation details. In order to have a dependable asynchronous execution mechanism, few more factors need our attention.

First, the sample of the usage of the Async annotation:

@Async
void doSomething() {
    // activities will be executed asynchronously
}

@Async("anExecutor")
Future<String> doThenReturnSomething(String id) {
    // will be executed asynchronously
}

Other possible return types:

JDK 8’s java.util.concurrent.CompletableFuture

boolean cancel(boolean mayInterruptIfRunning)
boolean complete(T value)

Spring’s org.springframework.util.concurrent.ListenableFuture 

void      addCallback(ListenableFutureCallback<? super T> callback)
void      addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback)

JBoss’s org.jboss.threads.AsyncFuture

Void asyncCancel(boolean interruptionDesired)
AsyncFuture.Status getStatus()

ThreadPoolTaskExecutor This implementation is the most commonly used one.

<task:executor
        id="executorWithCallerRunsPolicy"
        pool-size="5-25"
        queue-capacity="100"
        keep-alive="120"
        rejection-policy="CALLER_RUNS"/>
From Springframework document:
By default, the queue is unbounded, but this is rarely the desired configuration, because it can lead to OutOfMemoryErrors if enough tasks are added to that queue while all pool threads are busy.

TaskRejectedExceptionAbortPolicyDiscardPolicy or DiscardOldestPolicyCallerRunsPolicy

First, let’s consider the case, as mentioned above, when a task is rejected. By default, when a task is rejected, a thread pool executor will throw a TaskRejectedException. However, the rejection policy is actually configurable. The exception is thrown when using the default rejection policy which is the AbortPolicy implementation. For applications where some tasks can be skipped under heavy load, either the DiscardPolicy or DiscardOldestPolicy may be configured instead. Another option that works well for applications that need to throttle the submitted tasks under heavy load is the CallerRunsPolicy. Instead of throwing an exception or discarding tasks, that policy will simply force the thread that is calling the submit method to run the task itself. The idea is that such a caller will be busy while running that task and not able to submit other tasks immediately. Therefore it provides a simple way to throttle the incoming load while maintaining the limits of the thread pool and queue. Typically this allows the executor to "catch up" on the tasks it is handling and thereby frees up some capacity on the queue, in the pool, or both. Any of these options can be chosen from an enumeration of values available for the 'rejection-policy' attribute on the 'executor' element.
The keep-alive setting determines the time limit (in seconds) for which threads may remain idle before being terminated. If there are more than the core number of threads currently in the pool, after waiting this amount of time without processing a task, excess threads will get terminated.
Finally,
When actions are enclosed in tasks (such as FutureTask) either explicitly or via methods such as submit, these task objects catch and maintain computational exceptions, and so they do not cause abrupt termination, and the internal exceptions are not passed to this method. Please make sure that the calling method handles the exception properly.
Inside the asynchronous task, most likely, a remote service call or database access will be invoked. Please configure proper timeout so that thread will not be blocked or thread will not hang.