Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom annotation as Interceptor for a method logging

Java Gurus,

I am pretty new for annotations and haven't searched for this a lot, so please bear with me...

I would like to implement a Custom Annotation which will intercept a method call; to start with something very basic it can just print the methods name and parameters so that I could avoid the logger statement.

A sample call like this:

public MyAppObject findMyAppObjectById(Long id) throws MyCustomException {     log.debug("in findMyAppObjectById(" + id + ")");     //.... }    

can be converted into:

@LogMethodCall(Logger.DEBUG) public MyAppObject findMyAppObjectById(Long id) throws MyCustomException {     //.... }    

Could I get some hints about this?

like image 445
Bharat Sinha Avatar asked Aug 26 '12 13:08

Bharat Sinha


People also ask

Which annotation is used at method level?

@Bean. This annotation is used at the method level.

How do you write an interceptor in Java?

We can attach Interceptor to our class using @Interceptor annotation. Whenever a method in our class is called, the attached Interceptor will intercept that method invocation and execute its interceptor method. This can be achieved using @AroundInvoke annotation ( see example below ).

How do you pass value to custom annotations?

Annotations require constant values and a method parameter is dynamic. Show activity on this post. Annotation Usage: @CacheClear(pathToVersionId = "[0]") public int importByVersionId(Long versionTo){ ...... }


2 Answers

Based in your answers of my comments, you will not be able to do this with just annotations. You can, of course, create your annotations and create some reflective code that will detected then and execute some code, but this will not change your code too much, because you will need to call the parser method before you call your methods and I think that will not help you too much, since you will need to call the parser method before each call.

If you need the behavior that you mentioned (automatic call), you will need to combine your annotations with some AOP framework like Spring (plain Java) or AspectJ (AspectJ code). With then, you can set pointcuts and everytime this point is reached, some code may be executed. You can configure then to execute some code before and/or after method execution.

If the first scenario is sufficient, you can do something like:

Logger: enum

public enum Logger {     INFO,     DEBUG; } 

LogMethodCall: annotation

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;  @Retention( RetentionPolicy.RUNTIME ) // the annotation will be available during runtime @Target( ElementType.METHOD )         // this can just used in methods public @interface LogMethodCall {      Logger logLevel() default Logger.INFO;  } 

Person: annotated class

public class Person {      // will use the default log level (INFO)     @LogMethodCall     public void foo( int a ) {         System.out.println( "foo! " + a );     }      @LogMethodCall( logLevel = Logger.DEBUG )     public void bar( int b ) {         System.out.println( "bar! " + b );     }  } 

Utils: class with the log static method (this will perform the "parsing")

public class Utils {      public static void log( Object o, String methodName ) {          // gets the object class         Class klass = o.getClass();          // iterate over its methods         for ( Method m : klass.getMethods() ) {              // verify if the method is the wanted one             if ( m.getName().equals( methodName ) ) {                  // yes, it is                 // so, iterate over its annotations                 for ( Annotation a : m.getAnnotations() ) {                      // verify if it is a LogMethodCall annotation                     if ( a instanceof LogMethodCall ) {                          // yes, it is                         // so, cast it                         LogMethodCall lmc = ( LogMethodCall ) a;                          // verify the log level                         switch ( lmc.logLevel() ) {                             case INFO:                                 System.out.println( "performing info log for \"" + m.getName() + "\" method" );                                 break;                             case DEBUG:                                 System.out.println( "performing debug log for \"" + m.getName() + "\" method" );                                 break;                         }                      }                 }                  // method encountered, so the loop can be break                 break;              }          }      }  } 

AnnotationProcessing: class with code to test the annotation processing

public class AnnotationProcessing {      public static void main(String[] args) {          Person p = new Person();         Utils.log( p, "foo" );         p.foo( 2 );         Utils.log( p, "bar" );         p.bar( 3 );      } } 

Of course, you will need to improve my code to fit your needs. It is just a start point.

More about annotations:

  • http://docs.oracle.com/javase/1.5.0/docs/guide/language/annotations.html
  • http://docs.oracle.com/javase/tutorial/java/javaOO/annotations.html
  • http://tutorials.jenkov.com/java-reflection/annotations.html

More about AOP:

  • http://en.wikipedia.org/wiki/Aspect-oriented_programming
  • http://static.springsource.org/spring/docs/3.0.x/reference/aop.html
  • http://www.eclipse.org/aspectj/
like image 68
davidbuzatto Avatar answered Oct 05 '22 22:10

davidbuzatto


Use Spring AOP along with Java Annotation. Spring AOP negates the requirement for writing a util class for parsing of Java classes using Java Reflection.

Example -

  1. Custom Annotation -

     @Retention(RetentionPolicy.RUNTIME)  @Target(ElementType.METHOD)  public @interface A {                   boolean startA() default false;        boolean endA() default false;  } 
  2. Aspect-

      @Aspect   public class AAspect {       @Pointcut(value = "execution(* *.*(..))")       public void allMethods() {               LOGGER.debug("Inside all methods");       }       @Before("allMethods() && @annotation(A)")      public void startAProcess(JoinPoint pjp, A a) throws Throwable {           if (a.startA()) {                 //Do something      }  } 
  3. Enable AspectJ -

     @Configuration  @EnableAspectJAutoProxy  public class AConfig {   } 
  4. Use in code -

     @A(startA = true, endA = true)  public void setUp(){        //Do something- logic  } 
like image 22
Arijeet Saha Avatar answered Oct 05 '22 22:10

Arijeet Saha