2

I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this

In my client, I could get the annotation on my method using my Real Object, but not Proxy Object.

I used to think it was because of the lack of Retention Annotation on my own Annotation. But it doesn't work. Here is the code:

Annotation:

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

Interface:

public interface UserDao {
    void save();
    void update();
}

Implementation:

public class UserDaoImpl implements UserDao{
    @Override
    @MyAnnotation
    public void save() {
        System.out.println("save");
    }

    @Override
    public void update() {
        System.out.println("update");
    }
}

Client + driver application:

public class Client {
    public static void main(String[] args) {
        final UserDaoImpl dao = new UserDaoImpl();
        Method[] methods = dao.getClass().getMethods();
        for (Method m : methods){
            if(m.getAnnotation(MyAnnotation.class) != null)
                System.out.println("save method is enhanced");
        }

        UserDao proxy = (UserDao) Proxy.newProxyInstance(
            dao.getClass().getClassLoader(),
            dao.getClass().getInterfaces(),
            new InvocationHandler() {
                    @Override
                    public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
                        obj = dao;
                        if(method.getAnnotation(MyAnnotation.class) != null)
                            System.out.println("save method is enhanced2");
                        Object result = method.invoke(obj, args);
                        return result;
                    }
            }
        );

        proxy.save();
        System.out.println("-----------");
        proxy.update();
    }
}
Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
mik2sa
  • 21
  • 1
  • 2

1 Answers1

1

The dynamic proxy directly implements the given interface, it does not extend the implementing class as you seem to assume. I have fixed your non-compiling code, added some more log output and moved all classes into one of my packages because the Java compiler does not like the default package.

Driver application (updated):

package de.scrum_master.so;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Client {
  public static void main(String[] args) {
    final UserDaoImpl dao = new UserDaoImpl();
    Method[] methods = dao.getClass().getMethods();
    for (Method method : methods) {
      if (method.getAnnotation(MyAnnotation.class) != null) {
        System.out.println(method + " -> " + method.getDeclaringClass());
        System.out.println("impl method is enhanced");
      }
    }
    System.out.println("-----------");

    UserDao proxy = (UserDao) Proxy.newProxyInstance(
      dao.getClass().getClassLoader(),
      dao.getClass().getInterfaces(),
      new InvocationHandler() {
        @Override
        public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
          obj = dao;
          System.out.println(method + " -> " + method.getDeclaringClass());
          if (method.getAnnotation(MyAnnotation.class) != null)
            System.out.println("proxy method is enhanced");
          Object result = method.invoke(obj, args);
          return result;
        }
      });

    proxy.save();
    System.out.println("-----------");
    proxy.update();
  }
}

Console log:

public void de.scrum_master.so.UserDaoImpl.save() -> class de.scrum_master.so.UserDaoImpl
impl method is enhanced
-----------
public abstract void de.scrum_master.so.UserDao.save() -> interface de.scrum_master.so.UserDao
save
-----------
public abstract void de.scrum_master.so.UserDao.update() -> interface de.scrum_master.so.UserDao
update

Here you can see the difference between UserDaoImpl and the dynamic UserDao proxy.

I am unsure why you tagged this question with spring and aop because in your sample code there is no AOP and no Spring, but I suppose you want to use Spring AOP which is also based on dynamic proxies. There you have the option to enforce that also components implementing interfaces are to be created as CGLIB proxies, i.e. the proxies extend their base classes directly. Maybe then it works, but I am not sure how CGLIB proxies work in detail. If they would override each method, a JVM limitation would apply: Method annotations are never inherited by overriding methods.

So much for your technical problem. But what is it you really want to achieve? This is a mistake many people make here: They do not describe what they want to achieve but already have a technical solution in mind which might be inappropriate. This way they miss other options to solve their problem. Often the application design is flawed based on their false assumptions and could easily be fixed if they were not so fixated on their solution bias. Maybe if this does not help you, you create a new question, link it to this one, therein show your Spring AOP problem and describe what you want to achieve.


Update: If you want to access the original ("real") object from the proxy's invocation handler, you can do it like this:

Improved driver application:

package de.scrum_master.so;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Client {
  public static void main(String[] args) {
    final UserDaoImpl dao = new UserDaoImpl();
    Method[] methods = dao.getClass().getMethods();
    for (Method method : methods) {
      if (method.getAnnotation(MyAnnotation.class) != null) {
        System.out.println(method + " -> " + method.getDeclaringClass());
        System.out.println("impl method is enhanced");
      }
    }
    System.out.println("-----------");

    UserDao proxy = (UserDao) Proxy.newProxyInstance(
      dao.getClass().getClassLoader(),
      dao.getClass().getInterfaces(),
      new MyInvocationHandler(dao)
    );

    proxy.save();
    System.out.println("-----------");
    proxy.update();
  }

  private static class MyInvocationHandler implements InvocationHandler {
    private Object realObject;

    public MyInvocationHandler(Object realObject) {
      this.realObject = realObject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println(method + " -> " + method.getDeclaringClass());
      if (method.getAnnotation(MyAnnotation.class) != null)
        System.out.println("proxy method is enhanced");
      if (realObject.getClass().getMethod(method.getName(), method.getParameterTypes()).getAnnotation(MyAnnotation.class) != null)
        System.out.println("real object method is enhanced");
      return method.invoke(realObject, args);
    }

  }
}

Console log:

public void de.scrum_master.so.UserDaoImpl.save() -> class de.scrum_master.so.UserDaoImpl
impl method is enhanced
-----------
public abstract void de.scrum_master.so.UserDao.save() -> interface de.scrum_master.so.UserDao
real object method is enhanced
save
-----------
public abstract void de.scrum_master.so.UserDao.update() -> interface de.scrum_master.so.UserDao
update

Please note the line real object method is enhanced.

kriegaex
  • 63,017
  • 15
  • 111
  • 202