AOP and execute if annotation not present - java

I am using AOP to wrap an auditing framework around some services. I've come across an issue where we're auditing multiple events for the same action due to recursion. The quick solution it to mark the method as #NonAuditable and add it to my pointcut strategy. I am finding that the method still gets executed however.
Here's my existing strategy:
#Around(value="(" +
"execution( * my.class.services..*.*(..)) " +
") && "+
"#annotation(auditable)), argName="audit")
public Object audit(ProceedingJoinPoint call, Audit audit) {
...
...
}
How can I update my execution to say "only execute within the services package if it doesn't contain the #NonAuditable annotation?
I tried the following, which did not work:
#Around(value="(" +
"execution( * my.class.services..*.*(..)) " +
") && "+
"!#annotation(NonAuditable) && " +
"#annotation(auditable), argName="audit")
public Object audit(ProceedingJoinPoint call, Audit audit) {
...
...
}
UPDATE:
Here are some examples of some methods that gets audited
package my.class.services.UserService
import ...
...
#Auditable(message="Request for user", Context="Search")
public User getUser(long id){
User u = userRepository.getUser(id);
... // do work
}
\
package my.class.services.CarService
import ...
...
#Auditable(message="Request for traffic violations", Context="Search")
public List<Ticket> getTickets(long id){
List<Ticket> tix = dmvRepository.getUserTicketsById(id);
... // do work
}
#NonAuditable(message="Request for traffic violations", Context="Search")
public List<Ticket> getSpeedingTickets(long id){
List<Ticket> tickets = this.getTickets(id);
Collection filter = Collection.filter(...);
// do some other logic to just get speeding tickets.
return filter;
}
One problem I inherited is that getTickets is being called recursively by another method (getSpeedingTickets) and I am looking to be able to apply an Annotation (#NonAuditable) on that method to stop getTickets from being audited.

Okay, I thought about it again and think I have guessed what you mean. I think your situation is like this:
Annotations:
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Auditable {}
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface NonAuditable {}
Driver application:
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
Application application = new Application();
application.auditableAction("main");
application.inBetweenAction("main");
application.otherAction();
application.nonAuditableAction();
}
#Auditable
public void auditableAction(String caller) {
System.out.println(" auditableAction called by " + caller);
}
#NonAuditable
public void nonAuditableAction() {
auditableAction("nonAuditableAction");
inBetweenAction("nonAuditableAction");
}
public void otherAction() {
auditableAction("otherAction");
inBetweenAction("otherAction");
}
public void inBetweenAction(String caller) {
auditableAction(caller + " via inBetweenAction");
}
}
Now I assume you want to avoid auditing executions of the #Auditable method if called directly or indirectly by the #NonAuditable method. Correct? If so, the solution is to use a cflow() or cflowbelow() pointcut. Because such pointcuts cannot be evaluated statically but only dynamically during runtime, you might need to monitor the performance of your application after applying the aspect, but in many cases this is not a real problem. See for yourself. The solution looks as follows:
Aspect:
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class AuditAspect {
#Around(
"within(de.scrum_master.app..*) && " +
"execution(* *(..)) && " +
"#annotation(de.scrum_master.app.Auditable) && " +
"!cflow(#annotation(de.scrum_master.app.NonAuditable))"
)
public Object audit(ProceedingJoinPoint thisJoinPoint) throws Throwable {
System.out.println(thisJoinPoint);
return thisJoinPoint.proceed();
}
}
Console log:
execution(void de.scrum_master.app.Application.auditableAction(String))
auditableAction called by main
execution(void de.scrum_master.app.Application.auditableAction(String))
auditableAction called by main via inBetweenAction
execution(void de.scrum_master.app.Application.auditableAction(String))
auditableAction called by otherAction
execution(void de.scrum_master.app.Application.auditableAction(String))
auditableAction called by otherAction via inBetweenAction
auditableAction called by nonAuditableAction
auditableAction called by nonAuditableAction via inBetweenAction
Please note that nothing is logged before the last two lines.

Related

AspectJ: Pointcut to declare and retrieve an annotation of a method's parameter

I have read the following valuable links:
Spring AOP pointcut for annotated argument
How to write an Aspect pointcut based on an annotated parameter
AspectJ pointcut expression match parameter annotations at any position
Consider this request for a setter method
public void setSomething(#ParameterLevel(name="abc") String something){
this.something = something;
}
I have the following and works fine:
#Pointcut("execution(* *.*(#somepackage.ParameterLevel (*)))")
void parameterLevel01() {}
Now I want retrieve the #ParameterLevel annotation through a method's parameter such as the following:
#Pointcut("execution(* *.*(#somepackage.ParameterLevel (*)))")
void parameterLevel01(ParameterLevel parameterLevel) {} <--To be used directly in the advice method
The purpose is use the Annotation directly how a parameter in the advice method
Something similar such as:
#within(classLevel) for #ClassLevel in:
#ClassLevel
public class SomeClass {
...
}
#annotation(methodLevel) for #MethodLevel in:
#MethodLevel
public void somethingToDo(){
...
}
How accomplish this goal. Is possible? I am working with AspectJ 1.9.6
No matter if you use .., #MyAnnotation (*), .. or just #MyAnnotation (*), which only removes the ambiguity of possibly multiple matches, there is no direct way to bind a method argument annotation to an advice argument, only the method argument itself. This has not changed in AspectJ. You would have seen it mentioned in the release notes otherwise, because it would be a new feature.
So you will have to use the method from my other two answers which you have already linked to in your question, i.e. iterating over parameter types and annotations manually.
Somewhat off-topic, there is a very old Bugzilla ticket #233718 which is about binding multiple matched (annotated) parameters, but not about binding their annotations. It came up in a recent discussion I had with AspectJ maintainer Andy Clement. But even if this was implemented one day, it would not solve your problem.
I think you can take it from here and adapt my solution from the linked questions to your needs. Feel free to let me know if you have any follow-up questions about that, but it should be pretty straightforward. You might be able to optimise because you know the exact parameter position (think array index), if you feel so inclined, i.e. you don't need to iterate over all parameters.
Update: Here is a little MCVE for you. It is based on this answer and has been simplified to assume the annotation is always on the first parameter and the first parameter only.
Please learn what an MCVE is and provide one by yourself next time because it is your job, not mine. This was your free shot.
Marker annotation + driver application:
package de.scrum_master.app;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
#Retention(RUNTIME)
public #interface ParameterLevel {
String name();
}
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
new Application().doSomething("foo");
}
public void doSomething(#ParameterLevel(name="abc") String string) {}
}
Aspect:
package de.scrum_master.aspect;
import java.lang.annotation.Annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.SoftException;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import de.scrum_master.app.ParameterLevel;
#Aspect
public class ParameterLevelAspect {
#Before("execution(public * *(#de.scrum_master.app.ParameterLevel (*))) && args(string)")
public void beforeAdvice(JoinPoint thisJoinPoint, String string) {
System.out.println(thisJoinPoint + " -> " + string);
MethodSignature signature = (MethodSignature) thisJoinPoint.getSignature();
String methodName = signature.getMethod().getName();
Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
Annotation[] annotations;
try {
annotations = thisJoinPoint.getTarget().getClass()
.getMethod(methodName, parameterTypes)
.getParameterAnnotations()[0];
} catch (NoSuchMethodException | SecurityException e) {
throw new SoftException(e);
}
ParameterLevel parameterLevel = null;
for (Annotation annotation : annotations) {
if (annotation.annotationType() == ParameterLevel.class) {
parameterLevel = (ParameterLevel) annotation;
break;
}
}
assert parameterLevel != null;
System.out.println(" " + parameterLevel + " -> " + parameterLevel.name());
}
}
Console log:
execution(void de.scrum_master.app.Application.doSomething(String)) -> foo
#de.scrum_master.app.ParameterLevel(name="abc") -> abc

How to convert annotation-based into native AspectJ syntax

I have some troubles with aspectj and its syntax. I have something written on a java file and I want to translate it to an .aj file because I think that is easier, but I can't find a tutorial to follow.
This is my code:
#Aspect
public class Aspect{
#Pointcut("#annotation(annotationVariableName)")
public void annotationPointCutDefinition(Annotation annotationVariableName){
}
#Pointcut("execution(* *(..))")
public void atExecution(){}
#Around("annotationPointCutDefinition(withTransactionVariableName) && atExecution()")
public Object aroundAdvice(ProceedingJoinPoint joinPoint, Annotation annotationVariableName) throws Throwable {
boolean parameter= annotationVariableName.parameter();
Object returnObject = null;
try {
returnObject = joinPoint.proceed();
} catch (Throwable throwable) {
throw throwable;
}
return returnObject;
}
}
Can anyone help me with this? Thank you!
I have made up a little example MCVE relating to your comment about transaction management, so as to make the code and its log output a little clearer:
Annotation:
package de.scrum_master.app;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Transaction {
boolean myFlag();
}
Driver application:
Please note that two methods bear the annotation, one does not.
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
Application application = new Application();
application.doSomething();
application.doSomethingElse();
application.doSomethingWeird();
}
#Transaction(myFlag = true)
public void doSomething() {
System.out.println("Doing something");
}
public void doSomethingElse() {
System.out.println("Doing something else\n");
}
#Transaction(myFlag = false)
public void doSomethingWeird() {
System.out.println("Doing something weird");
throw new RuntimeException("oops");
}
}
Aspect:
package de.scrum_master.aspect;
import org.aspectj.lang.SoftException;
import de.scrum_master.app.Transaction;
public aspect TransactionAspect {
pointcut hasAnnotation(Transaction myAnnotation) : #annotation(myAnnotation);
pointcut methodExecution() : execution(* *(..));
Object around(Transaction myAnnotation) : methodExecution() && hasAnnotation(myAnnotation) {
System.out.println(thisJoinPoint + " -> " + myAnnotation);
boolean parameter = myAnnotation.myFlag();
System.out.println("Transaction start");
try {
Object result = proceed(myAnnotation);
System.out.println("Transaction commit\n");
return result;
} catch (Exception e) {
System.out.println("Transaction roll-back\n");
// Native AspectJ advices must not return checked exceptions, only runtime exceptions.
// So we soften the caught exception, just in case.
throw new SoftException(e);
}
}
}
Console log:
execution(void de.scrum_master.app.Application.doSomething()) -> #de.scrum_master.app.Transaction(myFlag=true)
Transaction start
Doing something
Transaction commit
Doing something else
execution(void de.scrum_master.app.Application.doSomethingWeird()) -> #de.scrum_master.app.Transaction(myFlag=false)
Transaction start
Doing something weird
Transaction roll-back
Exception in thread "main" org.aspectj.lang.SoftException
at de.scrum_master.app.Application.doSomethingWeird_aroundBody3$advice(Application.java:22)
at de.scrum_master.app.Application.doSomethingWeird(Application.java:1)
at de.scrum_master.app.Application.main(Application.java:8)
Caused by: java.lang.RuntimeException: oops
at de.scrum_master.app.Application.doSomethingWeird_aroundBody2(Application.java:23)
at de.scrum_master.app.Application.doSomethingWeird_aroundBody3$advice(Application.java:17)
... 2 more
By the way, if you are fine with anonymous pointcuts, there is no need to declare them separately. You can just do it this way:
Aspect variant with anonymous pointcut:
package de.scrum_master.aspect;
import org.aspectj.lang.SoftException;
import de.scrum_master.app.Transaction;
public aspect TransactionAspect {
Object around(Transaction myAnnotation) : execution(* *(..)) && #annotation(myAnnotation) {
System.out.println(thisJoinPoint + " -> " + myAnnotation);
boolean parameter = myAnnotation.myFlag();
System.out.println("Transaction start");
try {
Object result = proceed(myAnnotation);
System.out.println("Transaction commit\n");
return result;
} catch (Exception e) {
System.out.println("Transaction roll-back\n");
// Native AspectJ advices must not return checked exceptions, only runtime exceptions.
// So we soften the caught exception, just in case.
throw new SoftException(e);
}
}
}
Personally I found the following programmer guide useful myself although it's not really a tutorial : https://eclipse.org/aspectj/doc/next/progguide/index.html. Click on Pointcuts to get the basics of converting your pointcuts, advice is also covered on that page although it doesn't detail "around" advice but there is an example of that under production aspects
A quick search for a tutorial throws up the following (I haven't used this) :
http://o7planning.org/en/10257/java-aspect-oriented-programming-tutorial-with-aspectj

AspectJ: intercepting methods based on parameter values

I am using AspectJ to intercept a method called Request(String, String). For that I am using my own specified (marker) annotation. This is what the class looks like:
Class myclass {
public void Request(#Intercept String t, String u) {
// ...
}
}
The aspect that intercepts the #Intercept annotations:
#Aspect
class someAspect {
#Intercept
#Around("execution(public * * (#Interceptor (*), ..))")
public void capture(ProceedingJoinPoint pjp) {
// ...
}
}
However, my aspect is intercepting based on the annotated parameters. But I want the aspect to intercept the method request on specific values which the parameter t contains.
For example, if t == "t1", the method must be intercepted, otherwise not.
I was wondering if it is possible to do this in AspectJ (in combination with Spring AOP).
Actually there are a few issues with your code (I just reformatted it so it is at least readable):
In Java class names are usually in camel case, i.e. MyClass or SomeAspect instead of myclass or someAspect.
Method names in Java begin with lower case characters, i.e. request rather than Request.
You are mentioning two annotations #Intercept and #Interceptor. From now on I will assume that actually we are dealing with just one called #Intercept, okay?
You also annotate your aspect's advice with #Intercept, but I guess this is not intended, is it? It might lead to infinite recursion in another pointcut if the intercepting advice is intercepting itself...
As for your actual question, then answer is: sort of, but not statically within a pointcut (because parameters are only determined during runime) but dynamically, also during runtime. You have two options:
Option A: if-else within advice code
package de.scrum_master.app;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
public #interface Intercept {}
package de.scrum_master.app;
public class Application {
public static void one(#Intercept String string) {}
public static void two(String string, String string2) {}
public static void three(#Intercept String string, int i, int j) {}
public static void main(String[] args) {
one("foo");
two("foo", "bar");
three("foo", 11, 22);
one("bingo");
two("bingo", "bongo");
three("bingo", 33, 44);
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class InterceptorAspect {
#Pointcut("execution(public * *(#de.scrum_master.app.Intercept (*), ..)) && args(text, ..)")
public static void normalPointcut(String text) {}
#Around("normalPointcut(text)")
public Object capture(ProceedingJoinPoint thisJoinPoint, String text) {
if (text != "bingo")
return thisJoinPoint.proceed();
System.out.println(thisJoinPoint);
for (Object arg : thisJoinPoint.getArgs())
System.out.println(" " + arg);
// Do something before calling the original method
Object result = thisJoinPoint.proceed();
// Do something after calling the original method
return result;
}
}
Option B: use if() pointcut
The if() pointcut is a static method returning a boolean value based on the dynamic condition you want to test. The refactored aspect would look like this:
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class InterceptorAspect {
#Pointcut("if() && execution(public * *(#de.scrum_master.app.Intercept (*), ..)) && args(text, ..)")
public static boolean conditionalPointcut(String text) {
return text != "bingo";
}
#Around("conditionalPointcut(text)")
public Object capture(ProceedingJoinPoint thisJoinPoint, String text) {
System.out.println(thisJoinPoint);
for (Object arg : thisJoinPoint.getArgs())
System.out.println(" " + arg);
// Do something before calling the original method
Object result = thisJoinPoint.proceed();
// Do something after calling the original method
return result;
}
}
As you can see, the dynamic, parameter-based condition has moved into the pointcut which is no longer a void method with an empty body but a boolean method returning the result of the parameter check. Furthermore, the pointcut expressen got prepended by an if() && expression.
Console log:
The console output for both aspect variants is exactly the same:
execution(void de.scrum_master.app.Application.one(String))
foo
execution(void de.scrum_master.app.Application.three(String, int, int))
foo
11
22

how to do logging of method chaining using spring aop

I am using slf4j with Spring AOP for logging and Exception purpose.there are some methods in some classes which formed a method chaining. I am able to log at first method's entry and exit point but when this method called another method then AOP is logging only first method's entry and exit point.I want to log every method's entry and and exit point using #Around annotation here is Pseudo code to explain what i want
package com.sample;
public class Test implements T{
#Override
public void show() {
System.out.println("Test.show()");
test();
}
void Test(){
//Want to log entry and exit point of this method whenever this method called by any other method
//The method may belongs to same class or different package's different class
}
spring.xml is something like this
<bean id="exceptionAspect" class="com.sample.ExceptionAspect"/>
<bean id="test" class="com.sample.Test"/>
My Advise class look like
#Aspect
public class LoggingAspect {
#Around(value="execution (* com.sample.*.*(..))||"+
"execution(* some other package.*.*(..))")
public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
logger.info("Execution of : " + joinPoint.getSignature() + " Started");
joinPoint.proceed();
logger.info("Execution of : " + joinPoint.getSignature() + " completed");
}
}
Client class
package com.test;
public class App {
public static void main(String[] args) throws Exception {
ApplicationContext appContext = new ClassPathXmlApplicationContext(
"classpath:/META-INF/spring.xml");
T test=(T) appContext.getBean("test");
test.show();
}
Any Help is greatly appreciated..
What you are trying to do is not possible with Spring AOP (at least not without some refactoring of the advised methods). The reason for that is that Spring AOP is proxy based, which means for each bean it creates a proxy class and injects it instead of your implementation. A proxy has all the methods of the bean with added aspect functionality. So When you call a method of a bean (actually the proxy of the bean), the aspect code is executed and your method is then called by delegation. So when your method calls other methods the call are performed using the real beans, not the proxies of those - if any are present - hence you don't get the output you are expecting.
You can think of a proxy it looks somehow like that:
class MyBeanProxy implements MyBean {
MyBeanImpl theBean;
public void foo() {
// aspect code
theBean.foo();
}
public void bar() {
// aspect code
theBean.bar();
}
}
Where your bean is something like
interface MyBean {
foo();
bar();
}
#Component("my_bean")
class MyBeanImpl implements MyBean {
public void foo() {
System.out.println("foo");
bar();
}
public void bar() {
System.out.println("bar");
}
}
In the example above, when you call foo() via the proxy then the aspect code is executed, and the delegation to MyBeanImpl#foo() happens, where bar() is being called. Now it becomes obvious that the aspect code for bar() will not be executed.
Now how can you make it work?
1 - Refactor your code in such a way that for methods you want to have the aspect code executed for them the calls happen on the proxy object not on the bean itself. For that you can get the actual proxy and use it to call your methods.
public void foo() {
System.out.println("foo");
MyBean myBeanProxy = (MyBean) AopContext.currentProxy();
myBeanProxy.bar();
}
Note that this method is more of a hack than a clean way to do the job. For example it is obvious that myBeanProxy has no clue of the state of your current object.
2 - Refactor you code in such a way that bar() is in another bean which you can retrieve using your appContext.
3- Use AspectJ: Aspect code is injected into the target classes themselves (The real thing!)
Here is small example using AspectJ
Aspect
package com.aj;
import java.util.Arrays;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class MyAspect {
#Around("execution( * com.app.services.*.* (..) )")
public Object callDurationAdvice(ProceedingJoinPoint pjp) throws Throwable {
Signature signature = pjp.getSignature();
Object[] args = pjp.getArgs();
String argList = Arrays.toString(args);
System.out.println(signature.getDeclaringTypeName() +
"." + signature.getName() + "(" + argList + ") started");
long s = System.nanoTime();
Object proceed = pjp.proceed(args);
long e = System.nanoTime();
System.out.println(signature.getDeclaringTypeName() +
"." + signature.getName() + "(" + argList + ") ended after " +
((double)(e-s)/1000000) + " ms");
return proceed;
}
}
One class in some package witch should be target for the aspect
package com.app.services;
public class ServicesVersionInfo {
public static String getVersion() {
return getVersionNumber() + " " + getVersionStage();
}
public static String getVersionNumber() {
return "1.0.0";
}
public static String getVersionStage() {
return "ALPHA";
}
}
The App
package com.app;
import com.app.services.ServicesVersionInfo;
public class App {
public static void main(String[] args) {
System.out.println("App services version: " +
ServicesVersionInfo.getVersion());
}
}
Ran, this should output something lie that
com.app.services.ServicesVersionInfo.getVersion([]) started
com.app.services.ServicesVersionInfo.getVersionNumber([]) started
com.app.services.ServicesVersionInfo.getVersionNumber([]) ended after 0.004862 ms
com.app.services.ServicesVersionInfo.getVersionStage([]) started
com.app.services.ServicesVersionInfo.getVersionStage([]) ended after 0.005673 ms
com.app.services.ServicesVersionInfo.getVersion([]) ended after 0.378877 ms
App services version: 1.0.0 ALPHA
Finally here are some similar questions and further readings:
Spring AOP not working for method call inside another method
Get AOP proxy from the object itself
Spring AOP top problem #1 - aspects are not applied

Custom Annotations in Java

This is the first time I am trying to write a custom annotations in java.
I am not sure whether it is possible or not but wanted to give it a try before approaching another solution.
So here is the scenario, I have a lots of method that sends the data out from the application to a device. I have a requirement to log all these data in database.
I would like to create an annotation for this so that I can write the code in the annotation to log the data in database and then annotation all the methods with this annotation.
I can modify the code to log into the database but in that case I have to go in each method and place my code at correct place inorder to log them into database.
This is the reason I am looking for annotation based approach.
Is it possible what I am looking for or am I asking more.
Any pointers will be appreciated or If someone has different approach for my solution that will be really help full.
Instead of writing your own Annotations and processing them, have a look at what Spring provides, e.g. Interceptors:
Interceptors vs Aspects in Spring?
You can try below approach
package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#interface Todo {
public enum Priority {LOW, MEDIUM, HIGH}
String logInfo() default "Logging...";
Priority priority() default Priority.LOW;
}
package annotation;
public class BusinessLogic {
public BusinessLogic() {
super();
}
public void compltedMethod() {
System.out.println("This method is complete");
}
#Todo(priority = Todo.Priority.HIGH)
public void notYetStartedMethod() {
// No Code Written yet
}
#Todo(priority = Todo.Priority.MEDIUM, logInfo = "Inside DAO")
public void incompleteMethod1() {
//Some business logic is written
//But its not complete yet
}
#Todo(priority = Todo.Priority.LOW)
public void incompleteMethod2() {
//Some business logic is written
//But its not complete yet
}
}
package annotation;
import java.lang.reflect.Method;
public class TodoReport {
public TodoReport() {
super();
}
public static void main(String[] args) {
Class businessLogicClass = BusinessLogic.class;
for(Method method : businessLogicClass.getMethods()) {
Todo todoAnnotation = (Todo)method.getAnnotation(Todo.class);
if(todoAnnotation != null) {
System.out.println(" Method Name : " + method.getName());
System.out.println(" Author : " + todoAnnotation.logInfo());
System.out.println(" Priority : " + todoAnnotation.priority());
System.out.println(" --------------------------- ");
}
}
}
}

Categories