Groovy call operator throws MissingMethodException when used on a class field

假装没事ソ 提交于 2020-02-25 04:05:40

问题


I am trying to use call operator () overloading, but it does not work on class fields. What's wrong?

class Foo {
    void call(int x){
        println("x="+x)
    }
}

class MyCallable {
    Foo foo = new Foo()
}

Foo foo = new Foo() 
foo(5)  //works

MyCallable mc = new MyCallable()
mc.foo(2) //not works

But program terminated with exception:

Exception in thread "main" groovy.lang.MissingMethodException: No
signature of method: mpctests.MyCallable.foo() is applicable for
argument types: (java.lang.Integer) values: [2]

回答1:


You get MissingMethodException when you call mc.foo(5), because Groovy's invoke object method mechanism gets triggered. There is one thing worth explaining to get a better understanding about this situation. Your MyCallable class:

class MyCallable {
    Foo foo = new Foo()
}

gets compiled to something like this:

import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;

public class MyCallable implements GroovyObject {
    private Foo foo;

    public MyCallable() {
        CallSite[] var1 = $getCallSiteArray();
        Object var2 = var1[0].callConstructor(Foo.class);
        this.foo = (Foo)ScriptBytecodeAdapter.castToType(var2, Foo.class);
        MetaClass var3 = this.$getStaticMetaClass();
        this.metaClass = var3;
    }

    public Foo getFoo() {
        return this.foo;
    }

    public void setFoo(Foo var1) {
        this.foo = var1;
    }
}

Groovy also compiles every field access like mc.foo to a getter method call mc.getFoo(). So when you call mc.foo(5) it is clear for Groovy runtime that you expect to call a foo(5) method on mc object. And this method does not exist and MissingMethodException gets thrown.

However, it works if you create object def foo = new Foo() and then you call foo(5), because foo is an object and foo(5) is a strict instruction to invoke call(5) method on foo object (foo(5) is a shorthand version of foo.call(5)). The same situation would take place if you call mc() - Groovy would try to invoke mc.call() method. But when you say mc.foo(5) it's clear that you are trying to invoke foo(5) method.


If you want to use call operator on mc.foo field there are two options:

1. Use direct field access operator @

mc.@foo(5)

In this case you refer directly to foo field and you can use shorthand call operator.

2. Use with {} method

mc.with {
    foo(5)
}

In this case it is also a straightforward for Groovy runtime that you are accessing foo field and you can use call operator on it.

Alternatives

Using getter method:

mc.getFoo()(5)

Using method call() directly:

mc.foo.call(5) // equivalent of mc.getFoo().call(5)


来源:https://stackoverflow.com/questions/51727088/groovy-call-operator-throws-missingmethodexception-when-used-on-a-class-field

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!