如何在java中创建一个在方法上保留参数注释的动态代理?
我目前正在尝试代理一些现有的JAX/RS资源,以便使用Hibernate验证器的方法验证支持。但是,当我代理我的类(当前使用cglib 2.2)时,代理类中的参数上不存在FormParam注释,因此JAX/RS运行时(apache wink)不会填充参数。下面是一些测试代码,显示了以下内容:如何在java中创建一个在方法上保留参数注释的动态代理?,java,reflection,cglib,javassist,Java,Reflection,Cglib,Javassist,我目前正在尝试代理一些现有的JAX/RS资源,以便使用Hibernate验证器的方法验证支持。但是,当我代理我的类(当前使用cglib 2.2)时,代理类中的参数上不存在FormParam注释,因此JAX/RS运行时(apache wink)不会填充参数。下面是一些测试代码,显示了以下内容: import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*;
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
类没有代理:ProxyTester$ProxyMe
方法:aMethod有1个参数
参数0有1个批注
注释@ProxyTester.TestAnnotation()
类的javassist代理:ProxyTester$ProxyMe
方法:aMethod有1个参数
参数0具有0个批注
类的cglib代理:ProxyTester$ProxyMe
方法:aMethod有1个参数
参数0具有0个批注
类的jdk代理:ProxyTester$ProxyMe
方法:aMethod有1个参数
参数0具有0个批注
还有其他选择吗?从技术上讲,CGLib增强器只是从您的类扩展而来。我不知道这对您(对象的数量)是否可行,但是公开一个接口而不是类怎么样
Object p2 = Enhancer.create(resource.getClass(),
new Class[] { IResource.class },
new MethodInterceptor() {
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3)
throws Throwable {
return arg3.invokeSuper(arg0, arg2);
}
});
从增强类中删除注释并将其放入接口中。然后根据接口进行验证。对于许多这样的资源来说,这可能是很多锅炉板接口,但仍然比映射所有内容以形成支持对象或DTO要好得多。我怀疑,注释不会动态添加到代理实例中。(可能是因为这并不简单)。然而,在调用(或过滤)期间,可以从实际的方法实例获取注释。比如说,
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);
}
}
导入静态java.lang.annotation.ElementType.PARAMETER;
导入静态java.lang.annotation.RetentionPolicy.RUNTIME;
导入java.lang.annotation.annotation;
导入java.lang.annotation.Retention;
导入java.lang.annotation.Target;
导入java.lang.reflect.InvocationHandler;
导入java.lang.reflect.Method;
导入javassist.util.proxy.MethodHandler;
导入javassist.util.proxy.ProxyFactory;
导入net.sf.cglib.proxy.Enhancer;
导入net.sf.cglib.proxy.MethodInterceptor;
导入net.sf.cglib.proxy.MethodProxy;
公共类代理测试器
{
@目标({PARAMETER})
@保留(运行时)
公共静态@接口测试说明{}
公共静态接口iProxy{
无效方法(@TestAnnotation int param);
}
公共静态类ProxyMe实现IProxyMe{
公共无效方法(@TestAnnotation int param){
System.out.println(“调用的”+param);
System.out.println(“--------------------------”;
}
}
静态空转储注释(字符串类型、对象代理、对象forObject、字符串forMethod)
{
字符串className=forObject.getClass().getName();
System.out.println(类型+“类的代理:”+className);
对于(方法:proxy.getClass().getMethods()){
if(method.getName().equals(formMethod)){
打印注释(方法);
}
}
}
静态void打印注释(方法)
{
int paramCount=method.getParameterTypes().length;
System.out.println(“方法:“+Method.getName()+”具有“+paramCount+”参数”);
对于(Annotation[]paramAnnotations:method.getParameterAnnotations())
{
System.out.println(“注释:“+paramAnnotations.length”);
对于(注释:paramAnnotations)
{
System.out.println(“Annotation”+Annotation.toString());
}
}
}
静态对象javassitproxy(iproxy-in)引发异常
{
ProxyFactory pf=新的ProxyFactory();
pf.setSuperclass(在.getClass()中);
MethodHandler=newMethodHandler()
{
公共对象调用(对象自身、方法thisMethod、方法继续、对象[]args)抛出Throwable
{
if(thisMethod.getName().endsWith(“aMethod”))
打印注释(此方法);
返回procedure.invoke(self,args);
}
};
返回pf.create(新类[0],新对象[0],处理程序);
}
静态对象cglibProxy(iproxy-in)引发异常
{
对象p2=增强器.create(在.getClass()中,在.getClass()中,在.getInterfaces()中,
新方法拦截器()
{
公共对象截获(对象arg0、方法arg1、对象[]arg2、方法代理arg3)抛出Throwable
{
打印注释(arg1);
返回arg3.invokeSuper(arg0,arg2);
}
});
返回p2;
}
静态对象jdkProxy(中的最终iProxy)引发异常
{
返回java.lang.reflect.Proxy.newProxyInstance(在.getClass().getClassLoader()中,在.getClass().getInterfaces()中,
新的调用处理程序()
{
公共对象调用(对象代理、方法、对象[]args)抛出Throwable
{
打印注释(方法);
返回方法.invoke(in,args);
}
});
}
公共静态void main(字符串[]args)引发异常
{
IProxyMe proxyMe=新的proxyMe();
IProxyMe x=(IProxyMe)javassistProxy(proxyMe);
IProxyMe y=(IProxyMe)cglibProxy(proxyMe);
iproxy z=(iproxy)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(“>”);
x、 阿莫德(1);
y、 方法(2);
z、 方法(3);
}
}
我从未使用过cglib,但我知道
ClassPool myPool = new ClassPool(ClassPool.getDefault());
myPool.appendClassPath("./mods/bountymod/bountymod.jar");
CtClass ctTHIS = myPool.get(this.getClass().getName());
ctCreature.addMethod(CtNewMethod.copy(ctTHIS.getDeclaredMethod("checkCoinBounty"), ctCreature, null));
ctCreature.getDeclaredMethod("modifyFightSkill").instrument(new ExprEditor() {
public void edit(MethodCall m)
throws CannotCompileException {
if (m.getClassName().equals("com.wurmonline.server.players.Player")
&& m.getMethodName().equals("checkCoinAward")) {
String debugString = "";
if (bDebug)
debugString = "java.util.logging.Logger.getLogger(\"org.gotti.wurmunlimited.mods.bountymod.BountyMod"
+ "\").log(java.util.logging.Level.INFO, \"Overriding checkCoinAward to checkCoinBounty\");\n";
m.replace(debugString + "$_ = checkCoinBounty(player);");
}
}
});