如何在java中创建保留方法参数注释的动态代理?

2024-04-30

我目前正在尝试代理一些现有的 JAX/RS 资源,以便允许我使用 Hibernate Validator 的方法验证支持。但是,当我代理我的类(当前使用 cglib 2.2)时,代理类中的参数上不存在 FormParam 注释,因此 JAX/RS 运行时 (apache wink) 不会填充参数。这是一些显示这一点的测试代码:

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import javassist.util.proxy.ProxyFactory;

public class ProxyTester {

    @Target( { PARAMETER })
    @Retention(RUNTIME)
    public static @interface TestAnnotation {
    }

    public static interface IProxyMe {
        void aMethod(@TestAnnotation int param);
    }

    public static class ProxyMe implements IProxyMe {
            public void aMethod(@TestAnnotation int param) {
        }
    }

    static void dumpAnnotations(String type, Object proxy, Object forObject,
            String forMethod) {
        String className = forObject.getClass().getName();

        System.err.println(type + " proxy for Class: " + className);

        for (Method method : proxy.getClass().getMethods()) {
            if (method.getName().equals(forMethod)) {
                final int paramCount = method.getParameterTypes().length;
                System.err.println(" Method: " + method.getName() + " has "
                        + paramCount + " parameters");
                int i = 0;
                for (Annotation[] paramAnnotations : method
                        .getParameterAnnotations()) {
                    System.err.println("  Param " + (i++) + " has "
                            + paramAnnotations.length + " annotations");
                    for (Annotation annotation : paramAnnotations) {
                        System.err.println("   Annotation "
                                + annotation.toString());
                    }
                }
            }
        }
    }

    static Object javassistProxy(IProxyMe in) throws Exception {
        ProxyFactory pf = new ProxyFactory();
        pf.setSuperclass(in.getClass());
        Class c = pf.createClass();
        return c.newInstance();
    }

    static Object cglibProxy(IProxyMe in) throws Exception {
        Object p2 = Enhancer.create(in.getClass(), in.getClass()
                .getInterfaces(), new MethodInterceptor() {
            public Object intercept(Object arg0, Method arg1, Object[] arg2,
                    MethodProxy arg3) throws Throwable {
                return arg3.invokeSuper(arg0, arg2);
            }
        });
        return p2;

    }

    static Object jdkProxy(final IProxyMe in) throws Exception {
        return java.lang.reflect.Proxy.newProxyInstance(in.getClass()
                .getClassLoader(), in.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method,
                            Object[] args) throws Throwable {
                        return method.invoke(in, args);
                    }
                });
    }

    public static void main(String[] args) throws Exception {
        IProxyMe proxyMe = new ProxyMe();
        dumpAnnotations("no", proxyMe, proxyMe, "aMethod");
        dumpAnnotations("javassist", javassistProxy(proxyMe), proxyMe,
            "aMethod");
        dumpAnnotations("cglib", cglibProxy(proxyMe), proxyMe, "aMethod");

        dumpAnnotations("jdk", jdkProxy(proxyMe), proxyMe, "aMethod");
    }
}

这给了我以下输出:



no proxy for Class: ProxyTester$ProxyMe
 Method: aMethod has 1 parameters
  Param 0 has 1 annotations
   Annotation @ProxyTester.TestAnnotation()
javassist proxy for Class: ProxyTester$ProxyMe
 Method: aMethod has 1 parameters
  Param 0 has 0 annotations
cglib proxy for Class: ProxyTester$ProxyMe
 Method: aMethod has 1 parameters
  Param 0 has 0 annotations
jdk proxy for Class: ProxyTester$ProxyMe
 Method: aMethod has 1 parameters
  Param 0 has 0 annotations
  

还有其他选择吗?


我怀疑,注释不会动态添加到代理实例中。 (可能是因为它并不简单)。但是,可以在调用(或过滤)期间从实际方法实例获取注释。例如,

import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class ProxyTester
{
    @Target({ PARAMETER })
    @Retention(RUNTIME)
    public static @interface TestAnnotation {}

    public static interface IProxyMe {
        void aMethod(@TestAnnotation int param);
    }

    public static class ProxyMe implements IProxyMe {
        public void aMethod(@TestAnnotation int param) {
            System.out.println("Invoked " + param);
            System.out.println("-----------------");
        }
    }

    static void dumpAnnotations(String type, Object proxy, Object forObject, String forMethod)
    {
        String className = forObject.getClass().getName();
        System.out.println(type + " proxy for Class: " + className);

        for(Method method : proxy.getClass().getMethods()) {
            if(method.getName().equals(forMethod)) {
                printAnnotations(method);
            }
        }
    }

    static void printAnnotations(Method method)
    {
        int paramCount = method.getParameterTypes().length;
        System.out.println("Method: " + method.getName() + " has "  + paramCount + " parameters");

        for(Annotation[] paramAnnotations : method.getParameterAnnotations())
        {
            System.out.println("Annotations: " + paramAnnotations.length);

            for(Annotation annotation : paramAnnotations)
            {
                System.out.println("   Annotation " + annotation.toString());
            }
        }
    }

    static Object javassistProxy(IProxyMe in) throws Exception
    {
        ProxyFactory pf = new ProxyFactory();
        pf.setSuperclass(in.getClass());

        MethodHandler handler = new MethodHandler()
            {
                public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable
                {
                    if(thisMethod.getName().endsWith("aMethod"))
                        printAnnotations(thisMethod);

                    return proceed.invoke(self, args);
                }
            };
        return pf.create(new Class<?>[0], new Object[0], handler);
    }

    static Object cglibProxy(IProxyMe in) throws Exception
    {
        Object p2 = Enhancer.create(in.getClass(), in.getClass().getInterfaces(),
            new MethodInterceptor()
            {
                public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable
                {
                    printAnnotations(arg1);
                    return arg3.invokeSuper(arg0, arg2);
                }
            });

        return p2;
    }

    static Object jdkProxy(final IProxyMe in) throws Exception
    {
        return java.lang.reflect.Proxy.newProxyInstance(in.getClass().getClassLoader(), in.getClass().getInterfaces(),
            new InvocationHandler()
            {
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
                {
                    printAnnotations(method);
                    return method.invoke(in, args);
                }
            });
    }

    public static void main(String[] args) throws Exception
    {
        IProxyMe proxyMe = new ProxyMe();
        IProxyMe x = (IProxyMe) javassistProxy(proxyMe);
        IProxyMe y = (IProxyMe) cglibProxy(proxyMe);
        IProxyMe z = (IProxyMe) jdkProxy(proxyMe);

        dumpAnnotations("no", proxyMe, IProxyMe.class, "aMethod");
        dumpAnnotations("javassist", x, IProxyMe.class, "aMethod");
        dumpAnnotations("cglib", y, IProxyMe.class, "aMethod");
        dumpAnnotations("jdk", z, IProxyMe.class, "aMethod");

        System.out.println("<<<<< ---- Invoking methods ----- >>>>>");
        x.aMethod(1);
        y.aMethod(2);
        z.aMethod(3);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在java中创建保留方法参数注释的动态代理? 的相关文章

  • 策略模式还是命令模式?

    假设我有一个金融交易列表 我需要针对这些交易执行一系列验证规则 一个例子是我有一笔购买产品的交易 但是首先我需要验证交易中的帐户是否有足够的可用资金 产品没有售完等 由于这些规则 交易将是标记为拒绝 并应指定错误代码 当然 我正在考虑用一个
  • 将 MouseListener 添加到面板

    我正在尝试将鼠标操作添加到我的面板中 这就是程序应该做的事情 编写一个程序 允许用户通过按三下鼠标来指定一个三角形 第一次按下鼠标后 画一个小点 第二次按下鼠标后 绘制一条连接前两个点的线 第三次按下鼠标后 绘制整个三角形 第四次按下鼠标会
  • 对象数组的数组(二维数组)JNI

    我正在努力创建自定义对象类型 ShareStruct 的二维数组 jobjectArray ret jobjectArray ins jobjectArray outs jclass myClass env gt FindClass env
  • 如何在url请求中发送数组

    我的要求如下 我想给出演员姓名 开始日期 结束日期并获取他在该时期出演的所有电影 因此 我的服务请求是这样的 http localhost 8080 MovieDB GetJson name Actor startDate 20120101
  • Java 卡布局。多张卡中的一个组件

    一个组件 例如JLabel 在多张卡中使用CardLayout 目前看来该组件仅出现在它添加到的最后一张卡上 如果有办法做到这一点 我应该吗 这是不好的做法吗 或者有其他选择吗 你是对的 它只出现在 添加到的最后一张卡 中 但这与CardL
  • Spring中的ProxyFactoryBean

    有人可以解释一下吗代理工厂Bean http static springsource org spring docs current javadoc api org springframework aop framework ProxyFa
  • JUnit5 平台启动器 API - 如果没有至少一个测试引擎,则无法创建启动器

    我正在尝试升级我们的自动化测试套件的测试能力以接受 JUnit5 测试并遵循JUnit 平台启动器 API 说明 https junit org junit5 docs current user guide launcher api我收到错
  • JavaFX使节点覆盖父节点边框颜色

    我有一个如下所示的节点 仅使用 css 我希望标签覆盖其父边框颜色 因此标签下方的边框颜色部分变得不可见 我用来制作这个边框的CSS代码 fx border color black fx border width 3 fx border r
  • 无法在 Java 中输出正确的哈希值。怎么了?

    在我的 Android 应用程序中 我有一个 SHA256 哈希值 我必须使用 RIPEMD160 消息摘要算法进一步对其进行哈希值 我可以输出任何字符串的正确 sha256 和ripemd160 哈希值 但是当我尝试使用ripemd160
  • 具有 JPA 持久性的 Spring 状态机 - 存储库使用

    我试图弄清楚如何轻松使用 Spring 状态机 包括使用 JPA 进行持久化 这是我正在处理的问题 不兼容的数据类型 工厂和持久性 在程序的某个时刻 我想使用连接到用户的状态机 有用于此目的的存储库 项目spring statemachin
  • 如何在 JPA 和 Hibernate 中将数据库生成的列值定义为只读字段?

    使用 MariaDB 10 2 可以定义日期时间的默认值 例如创建和最后修改 我应该如何将此列作为只读字段访问 因为这个值应该只在数据库的控制之下 并且不应该从代码中修改 但我想在代码中读取这个属性 这很简单 只需设置insertable
  • 在尝试使用 GPS 之前如何检查 GPS 是否已启用

    我有以下代码 但效果不好 因为有时 GPS 需要很长时间 我该如何执行以下操作 检查GPS是否启用 如果启用了 GPS 请使用 GPS 否则请使用网络提供商 如果 GPS 时间超过 30 秒 请使用网络 我可以使用时间或 Thread sl
  • 用于层次结构树角色的 Spring Security / Java EE 解决方案

    我知道 Spring Security 非常适合标准角色和基于权限的授权 我不确定的是这种情况 系统中管理着 10 000 名员工 员工被组织成组织结构图 跨部门的谁向谁报告的树 其中一些员工是用户 这些用户仅被允许访问其职责范围内的员工
  • 拆分/标记化/扫描字符串并注意引号

    Java中是否有默认 简单的方法来分割字符串 但要注意引号或其他符号 例如 给定以下文本 There s a man that live next door in my neighborhood and he gets me down Ob
  • 如何从字符串中解析一个大整数? [复制]

    这个问题在这里已经有答案了 我有一个这样的方法 Integer parseInt myInt 不是这个整数变得很长 我得到以下异常 java lang NumberFormatException For input string 40001
  • 为什么无法从 WEB-INF 文件夹内加载 POSModel 文件?

    我在我的 Web 项目中使用 Spring MVC 我将模型文件放在 WEB INF 目录中 String taggerModelPath WEB INF lib en pos maxent bin String chunkerModelP
  • Java 中 JButton 的击键/热键

    最初我使用 JMenu 并建立热键以使用加速器工作 它运行得很好 现在我想在 JButton 中实现相同的行为 但我陷入困境 这是我编写的代码 请分享您的想法 以便我可以走上正确的道路 import javax swing import j
  • HTTP 状态 405 - 此 URL java servlet 不支持 HTTP 方法 POST [重复]

    这个问题在这里已经有答案了 我无法使页面正常工作 我有要发布的表单方法和我的 servlet 实现doPost 然而 它不断地向我表明我并不支持POST方法 我只是想做一个简单的网站并将值插入到我的 MySQL 数据库中 type Stat
  • java中使用多线程调用同一类的不同方法

    我有一个类 如下所示 具有三种方法 public class MyRunnable implements Runnable Override public void run what code need to write here to c
  • Java中单例的其他方式[重复]

    这个问题在这里已经有答案了 只是我在考虑编写单例类的其他方法 那么这个类是否被认为是单例类呢 public class MyClass static Myclass myclass static myclass new MyClass pr

随机推荐