自动委派java类的所有方法

自动委派java类的所有方法,java,reflection,delegates,Java,Reflection,Delegates,假设我有一个包含许多公共方法的类: public class MyClass { public void method1() {} public void method2() {} (...) public void methodN() {} } 现在我想创建一个包装类,它将所有方法委托给包装实例(委托): 现在,如果MyClass有很多方法,我需要重写它们中的每一个,它们或多或少都是相同的代码,只是“委托”。我想知道是否有可能在Java中自动调用一个方法(

假设我有一个包含许多公共方法的类:

public class MyClass {

    public void method1() {}
    public void method2() {}
    (...)
    public void methodN() {}

}
现在我想创建一个包装类,它将所有方法委托给包装实例(委托):

现在,如果MyClass有很多方法,我需要重写它们中的每一个,它们或多或少都是相同的代码,只是“委托”。我想知道是否有可能在Java中自动调用一个方法(因此包装器类需要说“嘿,如果你在我身上调用了一个方法,就去委托对象并在它身上调用这个方法”)

顺便说一句:我不能使用继承,因为委托不在我的控制之下。我只是从其他地方获得它的实例(另一种情况是如果MyClass是final)

注意:我不想生成IDE。我知道我可以在IntelliJ/Eclipse的帮助下完成,但我很好奇这是否可以在代码中完成


有什么建议可以实现这样的功能吗?(注意:我可能可以用一些脚本语言,比如php,在那里我可以使用php魔术函数来拦截调用)

你不应该让
扩展Myclass
和一个私有的
Myclass
对象一起——这真的是多余的,我想不出一个设计模式在哪里这样做是正确的。你的
包装类
Myclass
,因此你可以只使用它自己的字段和方法而不是调用它g
代表

编辑:如果
MyClass
final
,您将绕过故意声明,不允许通过“伪造”进行子类化“继承;除了你之外,我想不出还有谁愿意这样做,因为你控制着
WrapperClass
;但是,由于您控制着
WrapperClass
,因此不包装您不需要的所有内容实际上不仅仅是一种选择——这是正确的做法,因为您的对象不是
MyClass
,并且只应在您心里考虑的情况下表现得像一个对象


EDIT您刚刚通过将
MyClass
超类删除到您的
WrapperClass
,将您的问题更改为完全不同的意思;这有点糟糕,因为它使目前给出的所有答案无效。您应该打开另一个问题。

WrapperClass
中定义一个方法,即
delegate()
返回
MyClass

您可以使用反射来实现这一点,但调用方必须将方法名作为参数传递给公开的方法。而且在方法参数/重载方法等方面会有复杂的情况

顺便说一句:我不能使用继承,因为委托不在我的控制之下。我只是从别处获得它的实例(另一种情况是如果MyClass是final的话)

您发布的代码具有
公共类WrapperClass扩展MyClass


实际上,您当前的
WrapperClass
实现实际上是MyClass上的一个装饰程序

也许java的动态
代理可以帮助您。它只有在使用接口时才起作用。在这种情况下,我将调用接口
MyInterface
,并设置默认实现:

public class MyClass implements MyInterface {

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

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

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

    public static void main(String[] args) {
        MyClass wrapped = new MyClass();
        wrapped.method1();
        wrapped.method2();
        MyInterface wrapper = WrapperClass.wrap(wrapped);
        wrapper.method1();
        wrapper.method2();
    }

}
包装类实现如下所示:

public class WrapperClass extends MyClass implements MyInterface, InvocationHandler {

    private final MyClass delegate;

    public WrapperClass(MyClass delegate) {
        this.delegate = delegate;
    }

    public static MyInterface wrap(MyClass wrapped) {
        return (MyInterface) Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class[] { MyInterface.class }, new WrapperClass(wrapped));
    }

    //you may skip this definition, it is only for demonstration
    public void method1() {
        System.out.println("bar");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Method m = findMethod(this.getClass(), method);
        if (m != null) {
            return m.invoke(this, args);
        }
        m = findMethod(delegate.getClass(), method);
        if (m != null) {
            return m.invoke(delegate, args);
        }
        return null;
    }

    private Method findMethod(Class<?> clazz, Method method) throws Throwable {
        try {
            return clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

}
公共类包装器类扩展MyClass实现MyInterface、InvocationHandler{
私人班代表;
公共包装器类(MyClass委托){
this.delegate=委托;
}
公共静态MyInterface wrap(MyClass wrapped){
return(MyInterface)Proxy.newProxyInstance(MyClass.class.getClassLoader(),新类[]{MyInterface.class},新包装类(wrapped));
}
//您可以跳过此定义,它仅用于演示
公共无效方法1(){
系统输出打印项次(“bar”);
}
@凌驾
公共对象调用(对象代理、方法、对象[]args)抛出Throwable{
方法m=findMethod(this.getClass(),方法);
如果(m!=null){
返回m.invoke(this,args);
}
m=findMethod(delegate.getClass(),方法);
如果(m!=null){
返回m.invoke(委托,参数);
}
返回null;
}
私有方法findMethod(类clazz,方法Method)抛出可丢弃的{
试一试{
返回clazz.getDeclaredMethod(method.getName(),method.getParameterTypes());
}捕获(无此方法例外){
返回null;
}
}
}
请注意,此类:

  • 扩展
    MyClass
    ,以继承默认实现(任何其他实现都可以)
  • 实现
    Invocationhandler
    ,以允许代理进行反射
  • 可选地实现
    MyInterface
    (以满足装饰器模式)
此解决方案允许您重写特殊方法,但可以委托所有其他方法。这甚至可以用于包装类的子类


请注意,方法
findMethod
尚未捕获特殊情况

这个问题已经问了6个月了,@CoronA的精彩答案令人满意,并被@walkeros接受,但我想我会在这里补充一些东西,因为我认为这可以再推进一步

正如@CoronA在对其答案的评论中所讨论的,动态代理解决方案不必在
WrapperClass
中创建和维护一长串
MyClass
方法(即
public void methodN(){delegate.methodN();}
),而是将其移动到接口。问题是,您仍然需要为接口中的
MyClass
方法创建和维护一长串签名,这可能是一个bi
public class WrapperClass extends MyClass implements MyInterface, InvocationHandler {

    private final MyClass delegate;

    public WrapperClass(MyClass delegate) {
        this.delegate = delegate;
    }

    public static MyInterface wrap(MyClass wrapped) {
        return (MyInterface) Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class[] { MyInterface.class }, new WrapperClass(wrapped));
    }

    //you may skip this definition, it is only for demonstration
    public void method1() {
        System.out.println("bar");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Method m = findMethod(this.getClass(), method);
        if (m != null) {
            return m.invoke(this, args);
        }
        m = findMethod(delegate.getClass(), method);
        if (m != null) {
            return m.invoke(delegate, args);
        }
        return null;
    }

    private Method findMethod(Class<?> clazz, Method method) throws Throwable {
        try {
            return clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

}
public class MyClass {

    public void method1() { System.out.println("This is method 1 - " + this); } 
    public void method2() { System.out.println("This is method 2 - " + this); } 
    public void method3() { System.out.println("This is method 3 - " + this); } 
    public void methodN() { System.out.println("This is method N - " + this); }

}
public class WrapperClass extends MyClass {

    private MyClass delagate;

    public WrapperClass(MyClass delegate) { this.delagate = delegate; }

    @Override
    public void method2() {
        System.out.println("This is overridden method 2 - " + delagate);
    }

}
import java.lang.reflect.Method;

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

public class MyInterceptor extends MyClass implements MethodInterceptor {

    private Object realObj;

    public MyInterceptor(Object obj) { this.realObj = obj; }

    @Override
    public void method2() {
        System.out.println("This is overridden method 2 - " + realObj);
    }

    @Override
    public Object intercept(Object arg0, Method method, Object[] objects,
            MethodProxy methodProxy) throws Throwable {
        Method m = findMethod(this.getClass(), method);
        if (m != null) { return m.invoke(this, objects); }
        Object res = method.invoke(realObj, objects);
        return res;
    }

    private Method findMethod(Class<?> clazz, Method method) throws Throwable {
        try {
            return clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

}
import net.sf.cglib.proxy.Enhancer;

public class Main {

    private static MyClass unwrapped;
    private static WrapperClass wrapped;
    private static MyClass proxified;

    public static void main(String[] args) {
        unwrapped = new MyClass();
        System.out.println(">>> Methods from the unwrapped object:");
        unwrapped.method1();
        unwrapped.method2();
        unwrapped.method3();
        wrapped = new WrapperClass(unwrapped);
        System.out.println(">>> Methods from the wrapped object:");
        wrapped.method1();
        wrapped.method2();
        wrapped.method3();
        proxified = createProxy(unwrapped);
        System.out.println(">>> Methods from the proxy object:");
        proxified.method1();
        proxified.method2();
        proxified.method3();
    }

    @SuppressWarnings("unchecked")
    public static <T> T createProxy(T obj) {
        Enhancer e = new Enhancer();
        e.setSuperclass(obj.getClass());
        e.setCallback(new MyInterceptor(obj));
        T proxifiedObj = (T) e.create();
        return proxifiedObj;
    }

}

>>> Methods from the unwrapped object:
This is method 1 - MyClass@e26db62
This is method 2 - MyClass@e26db62
This is method 3 - MyClass@e26db62

>>> Methods from the wrapped object:
This is method 1 - WrapperClass@7b7035c6
This is overridden method 2 - MyClass@e26db62
This is method 3 - WrapperClass@7b7035c6

>>> Methods from the proxy object:
This is method 1 - MyClass@e26db62
This is overridden method 2 - MyClass@e26db62
This is method 3 - MyClass@e26db62
@CompileStatic
public class WrapperClass extends MyClass  {
    @Delegate private final MyClass delegate;

    public WrapperClass(MyClass delegate) {
        this.delagate = delegate;
    }

    //Done. That's it.

}
public class DelegationUtils {

    public static <I> I wrap(Class<I> iface, I wrapped) {
        return wrapInternally(iface, wrapped, new SimpleDecorator(wrapped));
    }

    private static <I> I wrapInternally (Class<I> iface, I wrapped, InvocationHandler handler) {
        return (I) Proxy.newProxyInstance(wrapped.getClass().getClassLoader(), new Class[] { iface }, handler);
    }

    private static class SimpleDecorator<T> implements InvocationHandler {

        private final T delegate;

        private SimpleDecorator(T delegate) {
            this.delegate = delegate;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Method m = findMethod(delegate.getClass(), method);
            if (m == null) {
                throw new NullPointerException("Found no method " + method + " in delegate: " + delegate);
            }
            return m.invoke(delegate, args);
        }
    }    

    private static Method findMethod(Class<?> clazz, Method method) throws Throwable {
        try {
            return clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
        } catch (NoSuchMethodException e) {
            return null;
        }
    }
}
public class Test {

    public  interface Test {
        public void sayHello ();
    }

    public static class TestImpl implements Test {
        @Override
        public void sayHello() {
            System.out.println("HELLO!");
        }
    }

    public static void main(String[] args) {
        Test proxy = DelegationUtils.wrap(Test.class, new TestImpl());
        proxy.sayHello();
    }
}
    // New ResultSet implementation
    public class MyResultSet implements InvocationHandler {
        ResultSet rs;
        PreparedStatement ps;
        private Method closeMethod;

        public MyResultSet(ResultSet rs, PreparedStatement ps) {
            super();
            this.rs = rs;
            this.ps = ps;
            try {
                closeMethod = ResultSet.class.getMethod("close",null);
            } catch (NoSuchMethodException | SecurityException e) {
                e.printStackTrace();
            }
        }

        public void close() {
            try {
                rs.close();
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }

        public static Object newInstance(ResultSet rs, PreparedStatement ps) {
            return java.lang.reflect.Proxy.newProxyInstance(rs.getClass().getClassLoader(), rs.getClass().getInterfaces(),
                    new MyResultSet(rs,ps));
        }

        public Object invoke(Object proxy, Method m, Object[] args) 
throws Throwable {
            Object result = null;
            try {
                Class declaringClass = m.getDeclaringClass();

                if (m.getName().compareTo("close")==0) {
                        close();
                } else {
                    result = m.invoke(rs, args);
                }
            } catch (InvocationTargetException e) {
                throw e.getTargetException();
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());

            } finally {
            }
            return result;
        }
    }
ResultSet prs = (ResultSet) MyResultSet.newInstance(rs,ps);