When I get method from class instance, and want to get #override annotation.
but method has not any annotation.
Is it impossible to get #override annotation?
code is below.
package com.test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import javax.annotation.Resource;
public class ReflectionTest {
public static void main(String[] args) throws Exception {
ChildHoge childHoge = new ChildHoge();
Method method = childHoge.getClass().getMethod("init");
for (Annotation s : method.getAnnotations()) {
System.out.println(s);
}
Method method2 = childHoge.getClass().getMethod("a");
for (Annotation a : method2.getAnnotations()) {
System.out.println(a); // =>#javax.annotation.Resource(mappedName=, shareable=true, type=class java.lang.Object, authenticationType=CONTAINER, lookup=, description=, name=)
}
}
}
class SuperHoge {
public void init() {
}
}
class ChildHoge extends SuperHoge {
#Override
public void init() {
super.init();
}
#Resource
public void a() {
}
}
#Retention(RetentionPolicy.SOURCE)
public #interface Override {
}
It has RetentionPolicy.SOURCE which are discarded by the compiler, which means it cannot be obtained at runtime. You can see this described in JLS 9.6.4.2.
If an annotation a corresponds to a type T, and T has a
(meta-)annotation m that corresponds to
java.lang.annotation.Retention, then:
If m has an element whose value is
java.lang.annotation.RetentionPolicy.SOURCE, then a Java compiler must
ensure that a is not present in the binary representation of the class
or interface in which a appears.
And the Javadoc for RetentionPolicy also describes this:
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
...
You can use Reflection API to check if the method is overridden or not
e.g.
class.getMethod("myMethod").getDeclaringClass();
If the class that's returned is your own, then it's not overridden; if it's something else, that subclass has overridden it.
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.
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.
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.
I have created a class in java as following:
public class TestAnnotations {
#Retention(value=RetentionPolicy.RUNTIME)
#Target(value=ElementType.FIELD)
protected #interface Addition
{
String location();
}
}
How can I get information about the annotation defined in the class using reflection. To be more specific, I am looking for the information like what is the type of Addition, of course name and its fields in it.
You can use Class#getDeclaredClasses() which
Returns an array of Class objects reflecting all the classes and
interfaces declared as members of the class represented by this Class
object.
You can then iterate over the array, check that that class is an annotation with Class#isAnnotation().
Example
public class Driver {
public static void main(String[] args) throws Exception {
Class<?>[] classes = Driver.class.getDeclaredClasses();
System.out.println(Arrays.toString(classes));
for (Class<?> clazz : classes) {
if (clazz.isAnnotation()) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
}
#Retention(value=RetentionPolicy.RUNTIME)
#Target(value=ElementType.FIELD)
protected #interface Addition
{
String location();
}
}
prints
[interface com.spring.Driver$Addition]
public abstract java.lang.String com.spring.Driver$Addition.location()