私はJavaからのGroovy呼び出しを発見し、このケースに問題があります:
グルーヴィーなファイルがあります: " test.groovy
"
a = 1.0
def mul2( x ) { 2.0 * x }
そして、私はこのようなJavaコードからそれを使いたいです
GroovyShell gs = new GroovyShell();
gs.parse( new File( ".../test.groovy" ) ).run();
System.out.printf( "a = %s%n", gs.evaluate("a") ); // ok
System.out.printf( "mul2(a) = %s%n", gs.evaluate( "mul2(a)" ) ); // error
エラーは:
groovy.lang.MissingMethodException: No signature of method: Script1.mul2() is applicable for argument types: (BigDecimal) values: [1.0]
evaluate()メソッドを使用して、groovyスクリプトで定義された関数にアクセスするにはどうすればよいですか?
最終的にのようなものを評価したいので、「評価」メソッドを使用する必要がありますMath.sin( a * mul2(Math.Pi) )
。
今私は4つの解決策を持っています(4つ目は私が探したものです):
...クラス(JavaではGroovyではない)...
public static abstract class ScriptClass extends Script
{
double mul2( double x )
{
return x * 2;
}
}
...コード...
CompilerConfiguration config = new CompilerConfiguration();
config.setScriptBaseClass(ScriptClass.class.getName());
GroovyShell gs = new GroovyShell(config);
System.out.printf( "result = %s%n", gs.evaluate("mul2(5.05)") );
それは機能しますが、コードはJavaであり、私が望むものではありませんが、それを行う必要がある人のためにここで注意します
groovyファイル:
double mul2( x ) { x * 2 }
a=mul2(3.33)
それを使用するJavaコード
GroovyClassLoader gcl = new GroovyClassLoader();
Class<?> r = gcl.parseClass( resourceToFile("/testx.groovy") );
CompilerConfiguration config = new CompilerConfiguration();
config.setScriptBaseClass(r.getName());
GroovyShell gs = new GroovyShell(gcl, config);
System.out.printf( "mul2(5.05) = %s%n", gs.evaluate("mul2(5.05)") );
// WARNING : call super.run() in evaluate expression to have access to variables defined in script
System.out.printf( "result = %s%n", gs.evaluate("super.run(); mul2(a) / 123.0") );
それはまさに私が欲しかったものです:-)
ここで何が起こっているのかを理解するには、説明する価値のあることが2つあります。指定したスクリプトには2つの異なるスコープがあります。
変数a
はGroovyShell
バインディングオブジェクトに格納されるため、すべてのgs.evaluate()
呼び出しで使用できます。この例を見てください:
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
final class ExecuteGroovyScriptExample {
public static void main(String[] args) {
final String script = "a = 1.0 \n" +
"def mul2(x) { 2.0 * x }\n";
final Binding binding = new Binding();
final GroovyShell gs = new GroovyShell(binding);
final Script sc = gs.parse(script);
sc.run();
System.out.printf("binding.getVariable(\"a\") == %s\n", binding.getVariable("a"));
}
}
この例を実行すると、次の出力が生成されます。
binding.getVariable("a") == 1.0
2つ目は、すべてのgs.evaluate()
呼び出しgroovy.lang.Script
が、まったく異なるコンテキストを持つ新しいクラスを生成することです。これが以下を呼び出す理由です:
gs.evaluate("mul2(a)")
このようなものを投げます:
Exception in thread "main" groovy.lang.MissingMethodException: No signature of method: Script2.mul2() is applicable for argument types: (BigDecimal) values: [1.0]
gs.evaluate("mul2(a)")
呼び出しから生成されるスクリプトクラスにはmul2(x)
メソッドが含まれていないためです。この呼び出しによって生成されるクラスは、次のようになります。
class Script2 extends groovy.lang.Script {
void run() {
mul2(a)
}
}
ただし、gs.parse(script)
contains mul2(x)
メソッドから返されるスクリプトクラスなので、呼び出すことはできますが、呼び出しとしてでgs.evaluate()
はなく、呼び出すことができますScript.invokeMethod(name, args)
。このようなもの:
import groovy.lang.GroovyShell;
import groovy.lang.Script;
final class ExecuteGroovyScriptExample {
public static void main(String[] args) {
final String script = "a = 1.0 \n" +
"def mul2(x) { 2.0 * x }\n";
final GroovyShell gs = new GroovyShell();
final Script sc = gs.parse(script);
sc.run();
System.out.printf("mul2(a) = %s%n", sc.invokeMethod("mul2", gs.evaluate("a")));
}
}
この例では、次の出力が生成されます。
mul2(a) = 2.00
mul2(x)
メソッドが呼び出された方法を見てください。まず、によって返されgs.parse(script)
たスクリプトをsc
変数に格納し、次の呼び出しによってこのスクリプトで定義されたメソッドを呼び出すことができるようにします。
sc.invokeMethod("mul2", gs.evaluate("a"));
この例では、a
によって変数の値を取得してgs.evaluate("a")
いますがbinding
、最初の例のオブジェクトを使用することもできます。また、a
変数が次のように定義されている場合は注意してください。
def a = 1.0
または
@groovy.transform.Field
def a = 1.0
binding
オブジェクトには保存されなくなり、最初のケースではスクリプトのローカル変数a
を定義し、2番目のケースではスクリプトクラスフィールドを定義しますa
。
または、次の呼び出しを実行する場合:
gs.evaluate("mul2(a)")
あるいは
gs.evaluate("Math.sin( a * mul2(Math.PI))")
入力Groovyスクリプトファイルを変更mul2(x)
し、関数定義をa
変数と同じスコープ内のクロージャーに置き換える必要があるため、binding
オブジェクトに格納されます。
a = 1.0
mul2 = { x -> 2.0 * x }
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加