Jenkins giải thích nhiều khai báo đối tượng trên một dòng


9

Đây không phải là một câu hỏi, mà là một câu chuyện cảnh báo: Tôi đã cố gắng tiết kiệm một số không gian và tuyên bố các biến của mình trong đường ống khai báo Jenkins như vậy:

int a, b, c

Sau đó, tôi khởi tạo chúng là:

a = b = c = 0

Trong mã của tôi, tôi sử dụng các số nguyên này làm bộ đếm trong một vòng lặp for. Kịch bản của tôi liên tục thất bại, một số trường hợp ngoại lệ được đưa ra:

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

và tôi biết chắc rằng danh sách của tôi là hợp lệ vì nó được mã hóa cứng. Vì vậy, tôi bắt đầu tự hỏi chuyện gì đang xảy ra với các quầy này và khi tôi gọi getClass () trên chúng, Jenkins vui vẻ nói với tôi rằng chúng không phải là số nguyên, mà là

org.codehaus.groovy.runtime.NullObject

Sau khi đổi mã thành

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

mọi thứ làm việc như một lá bùa. Chỉ muốn chia sẻ điều này. Có lẽ nó sẽ giúp ai đó tiết kiệm một số thất vọng.

Câu trả lời:


12

Các đường ống Jenkins thực thi mã Groovy theo kiểu truyền tiếp tục bằng trình thông dịch Groovy -cps . Đây không phải là vanilla Groovy, bạn có thể thực thi trực tiếp trong IDE hoặc trong Groovy Shell.

Groovy CPS chuyển đổi mã của bạn để hỗ trợ kiểu chuyển tiếp và biểu thức Groovy chính xác như:

a = b = c = 0

được chuyển đổi thành một cái gì đó trông giống như:

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

Vấn đề với biểu thức này trong trình thông dịch CPS là phép gán không trả về bất kỳ giá trị nào và do đó nullgiá trị được gán cho biến bvà điều tương tự xảy ra với biến a.

Nếu bạn muốn đào sâu hơn trong khối yêu cầu CPS, bạn có thể sao chép dự án Groovy-cps và viết một trường hợp thử nghiệm đơn giản trong com.cloudbees.groovy.cps.CpsTransformerTestlớp.

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

Sau đó, bạn có thể đặt một điểm dừng tại println cpsvà chạy trình gỡ lỗi. Khi bạn mở cửa sổ kiểm tra, bạn sẽ thấy hình ảnh tương tự như thế này:

nhập mô tả hình ảnh ở đây

Lưu ý phụ, hãy nhớ rằng trình biên dịch Groovy cũng chuyển đổi các phép gán dòng đơn của bạn khi biên dịch mã thành mã byte. Nếu bạn biên dịch một tập lệnh Groovy đơn giản như:

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

println "$a $b $c"

và sau đó bạn mở tệp lớp của nó trong IDE để dịch ngược mã byte thành tương đương Java, bạn sẽ thấy một cái gì đó như thế này:

//
// 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[]{"", " ", " ", ""}));
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.