您可以使用Groovy元编程来覆盖Java类上的私有方法吗? [英] Can you use Groovy meta programming to override a private method on a Java class

查看:182
本文介绍了您可以使用Groovy元编程来覆盖Java类上的私有方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图用meta编程重写一个Java类的私有方法。代码如下所示:

  // Java类
public class MyClass {

private ClassOfSomeSort property1;
private ClassOfSomeOtherSort property2;

public void init(){

property1 = new ClassOfSomeSort();
property2 = new ClassOfSomeOtherSort();

doSomethingCrazyExpensive();

$ b $ private void doSomethingCrazyExpensive(){
System.out.println(我正在做一些疯狂的事情);



// Groovy类
public class MyClassTest extends Specification {
$ b $ defMyClass实例被正确初始化() {b
b给定:
ExpandoMetaClass emc = new ExpandoMetaClass(MyClass,false)
emc.doSomethingCrazyExpensive = {println这里没什么可看的...}
emc .initialize()
def proxy = new groovy.util.Proxy()。wrap(new MyClass())
proxy.setMetaClass(emc)
当:
proxy.init ()
then:
proxy.property1!= null
proxy.property2!= null
}
}

问题在于doSomethingCrazyExpensive的重载实现没有被调用 - 我认为这是因为私有方法在内部由init()方法调用,没有通过metaClass调用。如果我直接调用myProxy.doSomethingCrazyExpensive(),则会调用重写的方法,所以元编程在某种程度上确实起作用。



有没有一种方法可以使用元编程在内部调用被重写的实现时调用Java类(或实例)上的方法吗?

解决方案

Groovy 作为运算符非常强大,并且可以使用Java中可见的具体类型创建代理。可悲的是,似乎它不能重写私有方法,尽管我设法改变了一个公共方法:

Java class:

  public class MyClass {

public void init(){
echo();
doSomethingCrazyExpensive();
}

public void echo(){System.out.println(echo); }
$ b $ private void doSomethingCrazyExpensive(){
System.out.println(我在做一些疯狂的事情);
}
}

Groovy测试:

  class MyClassTest扩展GroovyTestCase {
voidtest MyClass实例被正确初始化(){

def mock = [
doSomethingCrazyExpensive:{println'proxy crazy'},
echo:{println'proxy echo'}
] as MyClass

mock.init()

mock.doSomethingCrazyExpensive()
}
}



 代理echo 
我正在做一些疯狂的代价
代理疯狂的
code>

所以公共方法被拦截和修改,即使从Java调用,但不是私有方法。 b $ b

I'm trying to override a private method on a Java class using meta programming. The code looks something like this:

// Java class
public class MyClass{

    private ClassOfSomeSort property1;
    private ClassOfSomeOtherSort property2;

    public void init(){

        property1 = new ClassOfSomeSort();
        property2 = new ClassOfSomeOtherSort();

        doSomethingCrazyExpensive();
    }

    private void doSomethingCrazyExpensive(){
        System.out.println("I'm doing something crazy expensive");
    }
}

// Groovy class
public class MyClassTest extends Specification{

    def "MyClass instance gets initialised correctly"(){

        given:
        ExpandoMetaClass emc = new ExpandoMetaClass( MyClass, false )
        emc.doSomethingCrazyExpensive = { println "Nothing to see here..." }
        emc.initialize()
        def proxy = new groovy.util.Proxy().wrap( new MyClass() )
        proxy.setMetaClass( emc )
        when:
        proxy.init()
        then:
        proxy.property1 != null
        proxy.property2 != null     
    }
}

The problem is that the overridden implementation of doSomethingCrazyExpensive isn't called - I think that this is because the private method is called by the init() method internally and not called through the metaClass. If I call myProxy.doSomethingCrazyExpensive() directly, the overridden method is invoked, so the meta-programming does work to some degree.

Is there a way to use meta programming to override a method on a Java class (or instance) in such a way that the overridden implementation is called when it is invoked internally?

解决方案

Groovy as operator is quite powerful, and can create proxies out of concrete types whose changes are visible in Java. Sadly, seems like it can't override private methods, though i managed to change a public method:

Java class:

public class MyClass{

    public void init(){
        echo();
        doSomethingCrazyExpensive();
    }

    public void echo() { System.out.println("echo"); }

    private void doSomethingCrazyExpensive(){
        System.out.println("I'm doing something crazy expensive");
    }
}

Groovy test:

class MyClassTest extends GroovyTestCase {
    void "test MyClass instance gets initialised correctly"(){

        def mock = [
          doSomethingCrazyExpensive: { println 'proxy crazy' },
          echo: { println 'proxy echo' }
        ] as MyClass

        mock.init()

        mock.doSomethingCrazyExpensive()
    }
}

It prints:

proxy echo
I'm doing something crazy expensive
proxy crazy

So the public method got intercepted and changed, even when being called from Java, but not the private one.

这篇关于您可以使用Groovy元编程来覆盖Java类上的私有方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆