ProxyでMixin的な処理

が出来るんじゃないかと思ったけど、これは流石にかなり昔にやられてた。


ProxyでMixin - lambda {|diary| lambda { diary.succ! } }.call(hatena)


呼び出されたメソッドがどのクラス/インタフェースに載ってるのかをMethodのgetDeclaringClass()で取得出来るようなので、MixinInvocationHandlerの実装をメソッド名ベースでなくインタフェースベースに変えればオーバーロードでも平気になる。

class MixinInvocationHandler implements InvocationHandler {

    private Map objectMap = new HashMap();

    public MixinInvocationHandler(Object[] objects) {
        for (int i = 0; i < objects.length; i++) {
            Class[] interfaces = objects[i].getClass().getInterfaces();

            for (int j = 0; j < interfaces.length; j++) {
                objectMap.put(interfaces[j], objects[i]);
            }
        }
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = objectMap.get(method.getDeclaringClass());

        if (object == null)
            return null;

        return method.invoke(object, args);
    }

}

cat.run()はCatのrun()が呼ばれても良さそうなのに、getDeclaringClass()を取ると実際はCarの方のrun()が呼ばれている(Proxyを作る時に指定するインタフェースの順序に依存する。) invokeinterfaceのメソッド決定方法のせいかも。