I want to get the result of a method and then enqueue them into ActiveMQ. Hence, I decided to create an annotation(say #Enqueue("My_Queue")) that gets the result and send it to My_Queue.
#ResponseBody
#Enqueue("My_Queue")
#RequestMapping("/list")
public MyClass list() {
return myService.getAll();
}
And here is the annotation itself:
#Target(value = ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Enqueue {
/**
* The Name Of The Queue
*/
String value() default "General_Message_Queue";
}
So What should I do to create such an annotation(A-Z please)?
Aspects must be what your looking for. Since you're using Spring, have a look as Spring AOP: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html.
With the advice #AfterReturning and the pointcut #annotation(package.to.Enqueue), you'll be able to access the returned value each time a method annotated with #Enqueue is called: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-advice-after-returning.
You'll then be able to send it to the queue.
You need to write below code snap.
Class aClass = MyClass.class;
Annotation[] annotations = aClass.getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof Enqueue ){
Enqueue myAnnotation = (Enqueue ) annotation;
if(myAnnotation.name().equals("Enqueue")){
//do your work
System.out.println("value: " + myAnnotation.value());
}
}
}
Update :
Annotations are not "triggered"... you have to write code that looks for their presence and takes action.
The "code" can either be executed at runtime, but is more commonly executed at compile time using the Annotation Processing Tool to alter the source to inject extra, typically cross-cutting, code appropriate for the annotation.
Reference link : https://stackoverflow.com/a/13040933/1326692
Update : By seeing your comments it seems that you want something by which dynamically you can do your stuff before your annotation method call. For this you need to create proxy like given below.
1: MyInterface.java
public interface MyInterface {
void test();
}
2: Enqueue.java
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)
public #interface Enqueue {
public String value() default "General_Message_Queue";
}
3. MyClass.java
import java.lang.reflect.Proxy;
public class MyClass implements MyInterface {
#Enqueue
public void test() {
System.out.println("Inside test");
}
public static void main(String[] args) throws IllegalArgumentException, InstantiationException, IllegalAccessException {
MyInterface test = (MyInterface) getProxyInstance(MyClass.class, MyInterface.class);
test.test();
}
#SuppressWarnings("rawtypes")
public static Object getProxyInstance(Class clazz, Class interfaze) throws IllegalArgumentException,
InstantiationException, IllegalAccessException {
Object proxy =
Proxy.newProxyInstance(MethodInvocationHandler.class.getClassLoader(),
new Class[] {interfaze}, new MethodInvocationHandler(clazz.newInstance()));
return proxy;
}
}
4: MethodInvocationHandler.java
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MethodInvocationHandler implements InvocationHandler {
private Object proxied;
public MethodInvocationHandler(Object proxied) {
this.proxied = proxied;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method m = proxied.getClass().getMethod(method.getName(), method.getParameterTypes());
if (m.isAnnotationPresent(Enqueue.class)) {
// do your work here
System.out.println("Before " + m.getName() + " call..!");
/** also you can get annotation and access it's properties..! */
Enqueue annotation = m.getAnnotation(Enqueue.class);
System.out.println("name: " + annotation.value());
}
/** also you can get all the annotations if you want */
Annotation[] annotations = method.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
// do your annotation specific work here like this,
if (annotation instanceof Enqueue) {
// do your work here.
}
}
return method.invoke(proxied, args);
}
}
I hope it helps :)
If you are using spring-aop or any third party aop library then you can apply below code.
import java.util.ArrayList;
import java.util.Collection;
import org.apache.log4j.Logger;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class EnqueueServiceMonitor {
private static final Logger LOGGER = Logger
.getLogger(EnqueueServiceMonitor.class);
public EnqueueServiceMonitor() {
}
#AfterReturning(value = "#annotation(com.enqeue.annotation.Enqueue) && args(myClass,..)")
public void doProcess(MyClass myClass,
Exception ex) {
//do the code here. This method will call every time whenever your MyClass.list() method will be called.
//Or other method which have this annotation and return myClass object.
}
}
#ResponseBody
#Enqueue("My_Queue")
#RequestMapping("/list")
public MyClass list() {
return myService.getAll();
}
If your method have different return type then you have to write more aop advice for specific return type.
Related
I want to create an annotation which is only available to a specific type of return values.
For example this is my annotation.
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
public #interface MyAnnotation {
}
I also have an interface:
public interface MyInterface {
String generateKey();
}
An example class that implements my interface:
public class ExampleClass implements MyInterface {
#Override
public String generateKey() {
return "Whatever";
}
}
So after these, I want to configure my annotation in a way that it won't even compile if the return type is not implementing MyInterface.
In this case, I expect this to compile fine:
#MyAnnotation
public ExampleClass anExampleMethod() {
return new ExampleClass();
}
And this to not compile:
#MyAnnotation
public String anotherMethod() {
return "Whatever";
}
I wonder if this is possible in any way. Sure I can check if the parameters implements this interface in my Aspect class but it would be better to have this kind of protection in my library in order to prevent misuse of any annotation.
Helper classer:
These are directly from your example, just with package names and imports.
package de.scrum_master.app;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Retention(RUNTIME)
#Target(METHOD)
public #interface MyAnnotation {}
package de.scrum_master.app;
public interface MyInterface {
String generateKey();
}
package de.scrum_master.app;
public class ExampleClass implements MyInterface {
#Override
public String generateKey() {
return "Whatever";
}
}
Class which should not compile:
This class has some annotated and some non-annotated methods. One annotated method does not return MyInterface or any of its implementing classes. The goal is to fail compilation.
package de.scrum_master.app;
public class Application {
#MyAnnotation
public MyInterface annotatedMethodReturningInterface(int number) {
return new ExampleClass();
}
#MyAnnotation
public ExampleClass annotatedMethodReturningImplementingClass() {
return new ExampleClass();
}
#MyAnnotation
public String annotatedMethodReturningSomethingElse() {
// This one should not compile!
return "Whatever";
}
public MyInterface nonAnnotatedMethodReturningInterface(int number) {
return new ExampleClass();
}
public ExampleClass nonAnnotatedMethodReturningImplementingClass() {
return new ExampleClass();
}
public String nonAnnotatedMethodReturningSomethingElse() {
return "Whatever";
}
}
Convention-checking aspect (native AspectJ syntax):
package de.scrum_master.aspect;
import de.scrum_master.app.MyAnnotation;
import de.scrum_master.app.MyInterface;
public aspect AnnotationCheckerAspect {
declare error :
#annotation(MyAnnotation) && execution(* *(..)) && !execution(MyInterface+ *(..)) :
"Method annotated with #MyAnnotation must return MyInterface type";
}
This aspect checks for
all method executions
where the method has #MyAnnotation
but where the return type is different from MyInterface or any subtype or implementing class.
This is what the result looks like in Eclipse:
Of course the compilation error is just the same if you compile from command line or via AspectJ Maven plugin or similar.
If you do not like native syntax (I prefer it but for some incomprehensible reason other people seem to prefer #AspectJ style):
Convention-checking aspect (annotation-based #AspectJ syntax):
package de.scrum_master.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareError;
#Aspect
public class AnnotationCheckerAspect {
#DeclareError(
"#annotation(de.scrum_master.app.MyAnnotation) && " +
"execution(* *(..)) && " +
"!execution(de.scrum_master.app.MyInterface+ *(..))"
)
static final String wrongSignatureError =
"Method annotated with #MyAnnotation must return MyInterface type";
}
See also my related answers here:
https://stackoverflow.com/a/27121947/1082681
https://stackoverflow.com/a/54067850/1082681
https://stackoverflow.com/a/41700647/1082681
https://stackoverflow.com/a/27312472/1082681
https://stackoverflow.com/a/50126576/1082681
I'm trying to use byte buddy to intercept methods but have found that it only appears to work when you sub-type an interface.
The code snippet below demonstrates this, you can see "hello" being passed into the same "message" method of the 3 types but only the Interface subtype is intercepted.
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.attribute.AnnotationRetention;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Morph;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.This;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
class Sandbox {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
testIt(StaticClass.class).message("hello");
testIt(AbstractStaticClass.class).message("hello");
testIt(Interface.class).message("hello");
}
private static <T> T testIt(Class<T> aClass) throws IllegalAccessException, InstantiationException {
return new ByteBuddy().with(AnnotationRetention.ENABLED)
.subclass(aClass)
.method(
ElementMatchers.isAnnotatedWith(AnAnnotation.class)
).intercept(
MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(Invoker.class))
.to(new Interceptor()))
.make()
.load(Sandbox.class.getClassLoader())
.getLoaded()
.newInstance();
}
public interface Invoker {
Object invoke(Object[] args);
}
public static class Interceptor {
#RuntimeType
public Object intercept(#This Object proxy, #Origin Method method, #Morph(defaultMethod = true) Invoker invoker, #AllArguments Object[] args) {
return invoker.invoke(new Object[]{"there"});
}
}
public static class StaticClass {
#AnAnnotation
String message(String message) {
System.out.println(getClass().getName() + ": message: " + message);
return message;
}
}
public static abstract class AbstractStaticClass {
#AnAnnotation
String message(String message) {
System.out.println(getClass().getName() + ": message: " + message);
return message;
}
}
public interface Interface {
#AnAnnotation
default String message(String message) {
System.out.println(getClass().getName() + ": message: " + message);
return message;
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
private #interface AnAnnotation {}
}
I also found that if I changed the classes to inherit each other, like below, then the method doesn't execute at all for the AbstractStaticClass and StaticClass.
public static class StaticClass extends AbstractStaticClass { ... }
public static abstract class AbstractStaticClass implements Interface { ... }
public interface Interface { ... }
How can I intercept the methods of classes as well of interfaces?
Thank you
You are defining package-private methods which are only visible within a package. You are also using the default class injection strategy which will create a new class loader to load your injected class. At runtime, two packages are only equal if they have the same name and class loader, similarly to classes.
Actually, Byte Buddy overrides the methods for you as the class creation does not consider the target class loader. You can verify this by calling getDeclaredMethod on your generated class and invoking them. However, Java will not virtually dispatch such package-foreign methods even if they have the same signature. To define classes in the same class loader, you can use ClassLoadingStrategy.Default.INJECTION. Do however note that this strategy is discouraged as it relies on unsafe API. In Java 9+ you can use ClassLoadingStrategy.UsingLookup instead what is safe.
You can of course also change your methods to be public or protected.
Suppose I am initializing bean with the following code:
#Configuration
MyConfig {
#Bean
#MyAnnotation // how to know this from bean constructor or method?
MyBean myBean() {
MyBean ans = new MyBean();
/// setup ans
return ans;
}
}
Can I know from withing bean constructor or from withing bean's methods something about #MyAnnotation annotation?
Not from within myBean() method, which is obvious.
Well it's probably not the best or even correct way, but my first guess is to use current stack trace and it seems to work for me:
package yourpackage;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AspectJRawTest {
public static void main(String[] args) {
System.out.println("custom annotation playground");
ISomething something = new SomethingImpl();
something.annotatedMethod();
something.notAnnotatedMethod();
}
}
interface ISomething {
void annotatedMethod();
void notAnnotatedMethod();
}
class SomethingImpl implements ISomething {
#MyCustomAnnotation
public void annotatedMethod() {
System.out.println("I am annotated and something must be printed by an advice above.");
CalledFromAnnotatedMethod ca = new CalledFromAnnotatedMethod();
}
public void notAnnotatedMethod() {
System.out.println("I am not annotated and I will not get any special treatment.");
CalledFromAnnotatedMethod ca = new CalledFromAnnotatedMethod();
}
}
/**
* Imagine this is your bean which needs to know if any annotations affected it's construction
*/
class CalledFromAnnotatedMethod {
CalledFromAnnotatedMethod() {
List<Annotation> ants = new ArrayList<Annotation>();
for (StackTraceElement elt : Thread.currentThread().getStackTrace()) {
try {
Method m = Class.forName(elt.getClassName()).getMethod(elt.getMethodName());
ants.addAll(Arrays.asList(m.getAnnotations()));
} catch (ClassNotFoundException ignored) {
} catch (NoSuchMethodException ignored) {
}
}
System.out.println(ants);
}
}
Output clearly shows that I got an access to my annotation within object's constructor when it was called from annotated method:
custom annotation playground
I am annotated and something must be printed by an advice above.
[#yourpackage.MyCustomAnnotation(isRun=true)]
I am not annotated and I will not get any special treatment.
[]
Can I use AOP (AspectJ, Guice or other) to add annotations to classes that I cannot modify? My first use case would be adding persistence and binding annotations. I know I can write XML configuration files for JPA and JAXB but I am not aware of any way to do this for JSON binding.
I have looked for some examples/tutorials but have not found anything demonstrating this. IS it possible and if so, can someone provide a good example or better yet point me to some resources?
Yes, you can use AspectJ for that purpose (quoting the AspectJ cheat sheet, see also AspectJ Development Kit Developer's Notebook):
declare #type: C : #SomeAnnotation;
declares the annotation #SomeAnnotation on the type C.
declare #method: * C.foo*(..) : #SomeAnnotation;
declares the annotation #SomeAnnotation on all methods declared in C starting with foo.
declare #constructor: C.new(..) : #SomeAnnotation;
declares the annotation #SomeAnnotation on all constructors declared in C.
declare #field: * C.* : #SomeAnnotation;
declares the annotation #SomeAnnotation on all fields declared in C.
Just in case you wanted to ask: This feature is only supported in native AspectJ syntax, not in annotation-style #AspectJ syntax.
Update: Here is some sample code showing
how to add annotations to classes, interfaces and methods,
that even annotations marked as #Inherited are only inherited from class to subclass, never from interface to class and never to subclass methods (a typical Java caveat many developers are unaware of, see Emulate annotation inheritance for interfaces and methods with AspectJ for an explanation and a possible workaround),
how via AspectJ you can still apply an annotation to classes implementing an interface via + subclass specifier, e.g. in MyInterface+,
how another aspect can immediately see and utilise annotations added via declare #type, declare #method etc.
Class hierarchy including abstract base classes and an interface:
package de.scrum_master.app;
public interface MyInterface {
void doSomething();
int doSomethingElse(int a, int b);
String sayHelloTo(String name);
}
package de.scrum_master.app;
public abstract class NormalBase implements MyInterface {
#Override
public abstract void doSomething();
#Override
public int doSomethingElse(int a, int b) {
return a + b;
}
#Override
public abstract String sayHelloTo(String name);
}
package de.scrum_master.app;
public class Normal extends NormalBase {
#Override
public void doSomething() {
//System.out.println("Doing something normal");
}
#Override
public String sayHelloTo(String name) {
return "A normal hello to " + name;
}
public void doNothing() {
//System.out.println("Being lazy in a normal way");
}
}
package de.scrum_master.app;
public abstract class SpecialBase {
public abstract void doFoo();
public abstract void makeBar();
}
package de.scrum_master.app;
public class Special extends SpecialBase implements MyInterface {
#Override
public void doSomething() {
//System.out.println("Doing something special");
}
#Override
public int doSomethingElse(int a, int b) {
return a * b;
}
#Override
public String sayHelloTo(String name) {
return "A special hello to " + name;
}
#Override
public void doFoo() {
//System.out.println("Doing foo");
}
#Override
public void makeBar() {
//System.out.println("Making bar");
}
public int doZot() {
return 11;
}
public String makeBlah() {
return "Blah";
}
}
package de.scrum_master.app;
public class SpecialTwo extends SpecialBase {
#Override
public void doFoo() {
//System.out.println("Doing foo");
}
#Override
public void makeBar() {
//System.out.println("Making bar");
}
public String doXxx() {
return "Xxx";
}
public int makeBlah() {
return 22;
}
}
Driver application creating all kinds of object, calling all kinds of methods:
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
System.out.println("Normal instance");
Normal normal = new Normal();
normal.doSomething();
normal.doSomethingElse(3, 5);
normal.sayHelloTo("John");
normal.doNothing();
System.out.println("\nNormal instance as NormalBase");
NormalBase normalBase = normal;
normalBase.doSomething();
normalBase.doSomethingElse(3, 5);
normalBase.sayHelloTo("John");
System.out.println("\nNormal instance as MyInterface");
MyInterface myInterface = normal;
myInterface.doSomething();
myInterface.doSomethingElse(3, 5);
myInterface.sayHelloTo("John");
System.out.println("\nSpecial instance");
Special special = new Special();
special.doSomething();
special.doSomethingElse(7, 8);
special.doFoo();
special.doZot();
special.makeBar();
special.makeBlah();
special.sayHelloTo("Jane");
System.out.println("\nSpecial instance as SpecialBase");
SpecialBase specialBase = special;
specialBase.doFoo();
specialBase.makeBar();
System.out.println("\nSpecial instance as MyInterface");
myInterface = special;
myInterface.doSomething();
myInterface.doSomethingElse(7, 8);
myInterface.sayHelloTo("Jane");
System.out.println("\nSpecialTwo instance");
SpecialTwo specialTwo = new SpecialTwo();
specialTwo.doFoo();
specialTwo.makeBar();
specialTwo.makeBlah();
specialTwo.doXxx();
System.out.println("\nSpecialTwo instance as SpecialBase");
specialBase = specialTwo;
specialBase.doFoo();
specialBase.makeBar();
}
}
Some marker annotations later to be added to interfaces, classes, methods by an aspect:
package de.scrum_master.app;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface InterfaceMarker {}
package de.scrum_master.app;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface ClassMarker {}
package de.scrum_master.app;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface MethodMarker {}
Aspect adding annotations to interfaces, classes, methods:
package de.scrum_master.aspect;
import de.scrum_master.app.ClassMarker;
import de.scrum_master.app.InterfaceMarker;
import de.scrum_master.app.MethodMarker;
import de.scrum_master.app.MyInterface;
import de.scrum_master.app.SpecialBase;
public aspect AnnotationGenerator {
declare #type : MyInterface+ : #InterfaceMarker;
declare #type : SpecialBase : #ClassMarker;
declare #method : * say*(..) : #MethodMarker;
}
Aspect logging initialisation of annotated classes and execution of annotated methods:
package de.scrum_master.aspect;
import de.scrum_master.app.ClassMarker;
import de.scrum_master.app.InterfaceMarker;
import de.scrum_master.app.MethodMarker;
public aspect MarkedObjectLogger {
before() : #annotation(InterfaceMarker) {
System.out.println(thisJoinPoint + " -> #InterfaceMarker");
}
before() : #annotation(ClassMarker) {
System.out.println(thisJoinPoint + " -> #ClassMarker");
}
before() : #annotation(MethodMarker) && execution(* *(..)) {
System.out.println(thisJoinPoint + " -> #MethodMarker");
}
}
Console log:
Normal instance
staticinitialization(de.scrum_master.app.NormalBase.<clinit>) -> #InterfaceMarker
staticinitialization(de.scrum_master.app.Normal.<clinit>) -> #InterfaceMarker
execution(String de.scrum_master.app.Normal.sayHelloTo(String)) -> #MethodMarker
Normal instance as NormalBase
execution(String de.scrum_master.app.Normal.sayHelloTo(String)) -> #MethodMarker
Normal instance as MyInterface
execution(String de.scrum_master.app.Normal.sayHelloTo(String)) -> #MethodMarker
Special instance
staticinitialization(de.scrum_master.app.SpecialBase.<clinit>) -> #ClassMarker
staticinitialization(de.scrum_master.app.Special.<clinit>) -> #InterfaceMarker
staticinitialization(de.scrum_master.app.Special.<clinit>) -> #ClassMarker
execution(String de.scrum_master.app.Special.sayHelloTo(String)) -> #MethodMarker
Special instance as SpecialBase
Special instance as MyInterface
execution(String de.scrum_master.app.Special.sayHelloTo(String)) -> #MethodMarker
SpecialTwo instance
staticinitialization(de.scrum_master.app.SpecialTwo.<clinit>) -> #ClassMarker
SpecialTwo instance as SpecialBase
Try removing the + from declare #type : MyInterface+ and see how all log lines mentioning #InterfaceMarker vanish because interface annotations really are not inherited by implementing classes.
Unfortunately it seems that annotation inheritance is severely restricted by the fact that only class-level annotations from classes (and not interfaces) can be inherited.
Consider this code:
interface Foo {
#A
void bar(String str, #B int i);
}
class FooImpl implements Foo {
void bar(String str, #B int i) { ... }
}
If I have an instance of FooImpl is it possible to discover if the method has been annotated with A (either in the class (easy) or in the implemented interface)?
What about the method parameter? Is it possible to dicover if and which parameter has been annotated with B?
It seems that this is not possible with AspectJ and I need to use Java Reflection.
How would a solid solution look like?
Its possible use getInterfaces() on the class object and query the result.
parameter annotation
package mawi12345;
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 B {
int version() default 0;
}
method annotation
package mawi12345;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#Inherited
public #interface Revision {
int minor() default 0;
int major() default 1;
}
interface with annotations
package mawi12345;
public interface Foo {
#Revision(minor=1, major=3)
public void setMark(#B(version=3) int mark);
}
class with annotations and the Foo interface
package mawi12345;
public class Test implements Foo {
public void setMark(int mark) {
}
#Revision(minor=2, major=4)
public boolean isPassed() {
return true;
}
}
Test Class
package mawi12345;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class ReflectionTest {
public static void printAnnotations(Class<?> clazz) {
// array of methods
Method[] methods = clazz.getDeclaredMethods();
System.out.println("found "+methods.length+" methods");
for (int i=0; i<methods.length; i++) {
// get the annotations of this method
Annotation[] methodAnnotations = methods[i].getAnnotations();
// if you only wont to check for one annotation use getAnnotation(Class<T>)
for (Annotation methodAnnotation : methodAnnotations) {
System.out.println(methodAnnotation);
}
// get the parameter annotations (2d array)
Annotation[][] parameterAnnotations = methods[i].getParameterAnnotations();
// get an array of parameters
Class<?>[] parameters = methods[i].getParameterTypes();
for(int x=0; x<parameterAnnotations.length; x++) {
Class<?> parameter = parameters[x];
for(Annotation annotation : parameterAnnotations[x]){
// print the parameter name and his annotation
System.out.println(parameter.getName() + " " + annotation);
}
}
}
}
/**
* #param args
*/
public static void main(String[] args) {
// create Test object
Test test = new Test();
// get the class
Class<?> clazz = test.getClass();
System.out.println("Class Test");
// print annotations
printAnnotations(clazz);
System.out.println();
// get the interfaces of the class
Class<?>[] interfaces = clazz.getInterfaces();
System.out.println("found "+interfaces.length+" interfaces");
// print annotations for each interface
for (Class<?> type : interfaces) {
System.out.println(type);
printAnnotations(type);
}
}
}
Output
Class Test
found 2 methods
#mawi12345.Revision(minor=2, major=4)
found 1 interfaces
interface mawi12345.Foo
found 1 methods
#mawi12345.Revision(minor=1, major=3)
int #mawi12345.B(version=3)