Jenkinsによる1行の複数のオブジェクト宣言の解釈


9

これは問題ではありませんが、むしろ注意書きです。スペースを節約するために、Jenkins宣言型パイプラインで変数を次のように宣言しました。

int a, b, c

次に、それらを次のように初期化しました。

a = b = c = 0

私のコードでは、これらの整数をforループのカウンターとして使用しています。スクリプトが何度も何度も失敗し続け、いくつかの例外がスローされました。

java.lang.NullPointerException: Cannot invoke method next() on null object

そして、ハードコードされていたので、私のリストが有効であることは確かでした。したがって、これらのカウンターで何が起こっているのか疑問に思い始め、それらに対してgetClass()を呼び出したとき、Jenkinsは喜んでそれらが整数ではなく、

org.codehaus.groovy.runtime.NullObject

コードを変更した後

int a = 0
int b = 0
int c = 0

すべてが魅力のように機能しました。これを共有したかっただけです。多分それは誰かがいくつかの欲求不満を救うのを助けるでしょう。

回答:


12

Jenkinsパイプラインは、groovy-cpsインタープリターを使用して、継続渡しスタイルでGroovyコードを実行します。これは、IDEまたはGroovy Shellで直接実行できる単純なGroovyではありません。

Groovy CPSはコードを変換して、継続渡しスタイルと次のような正しいGroovy式をサポートします。

a = b = c = 0

より似たものに変換されます:

eval(
  var("a"), 
  assign(
    eval(
      var("b"), 
      assign(
        eval(
          var("c"), 
          assign(0)
        )
      )
    )
  )
)

CPSインタープリターでのこの式の問題は、割り当てが値を返さないため、null値が変数bに割り当てられ、同じことが変数にも発生することですa

CPS呼び出しブロックをさらに掘り下げたい場合は、groovy-cpsプロジェクトのクローンを作成し、com.cloudbees.groovy.cps.CpsTransformerTestクラスに簡単なテストケースを記述できます。

@Test
void testMultiVariablesInlineCPS() {
    def cps = parseCps('''
int a, b, c
a = b = c = 0
''')
    println cps
}

次に、ブレークポイントをに置いprintln cpsてデバッガを実行できます。検査ウィンドウを開くと、次のような画像が表示されます。

ここに画像の説明を入力してください

ちなみに、Groovyコンパイラーは、コードをバイトコードにコンパイルするときに単一行の割り当ても変換することに注意してください。次のような単純なGroovyスクリプトをコンパイルすると、

int a, b, c
a = b = c = 0

println "$a $b $c"

次に、そのクラスファイルをIDEで開いて、バイトコードをJavaの同等のものに逆コンパイルすると、次のようになります。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.GStringImpl;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.callsite.CallSite;

public class test extends Script {
    public test() {
        CallSite[] var1 = $getCallSiteArray();
    }

    public test(Binding context) {
        CallSite[] var2 = $getCallSiteArray();
        super(context);
    }

    public static void main(String... args) {
        CallSite[] var1 = $getCallSiteArray();
        var1[0].call(InvokerHelper.class, test.class, args);
    }

    public Object run() {
        CallSite[] var1 = $getCallSiteArray();
        int a = 0;
        int b = 0;
        int c = 0;
        byte var5 = 0;
        return var1[1].callCurrent(this, new GStringImpl(new Object[]{Integer.valueOf(var5), Integer.valueOf(var5), Integer.valueOf(var5)}, new String[]{"", " ", " ", ""}));
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.