2013-07-18 41 views
3

通過我自己的插件,我需要知道Jenkins從站的工作區中是否存在文件。但該文件無法找到,而它確實存在於從站(D:\workspace\JOB_NAME\test.txt)。Jenkins插件無法訪問從站上的文件

public class MyBuilder extends Builder implements Serializable { 

    private static final long serialVersionUID = 1L; 

    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) 
      throws InterruptedException, IOException { 

     FilePath fp = new FilePath(build.getWorkspace(), "test.txt"); 

     String result = fp.act(new FileCallable<String>() { 
      private static final long serialVersionUID = 1L; 

      @Override 
      public String invoke(File file, VirtualChannel channel) throws IOException, InterruptedException { 
       if (file.getAbsoluteFile().exists()){ 
        return file.getName() + " exists."; 
       } else { 
        return file.getName() + " doesn't exist."; 
       } 
      } 
     }); 

     System.out.println("result: " + result); 

結果:

FATAL: remote file operation failed: D:\workspace\JOB_NAME\test.txt at [email protected]:Slave 
hudson.util.IOException2: remote file operation failed: D:\workspace\JOB_NAME\test.txt at [email protected]:Slave 
    at hudson.FilePath.act(FilePath.java:900) 
    at hudson.FilePath.act(FilePath.java:877) 
    at com.company.tlb.proj.MyBuilder.perform(Unknown Source) 
    at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:19) 
    at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:804) 
    at hudson.model.Build$BuildExecution.build(Build.java:199) 
    at hudson.model.Build$BuildExecution.doRun(Build.java:160) 
    at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:586) 
    at hudson.model.Run.execute(Run.java:1575) 
    at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:46) 
    at hudson.model.ResourceController.execute(ResourceController.java:88) 
    at hudson.model.Executor.run(Executor.java:237) 
Caused by: java.io.IOException: Unable to serialize [email protected] 
    at hudson.remoting.UserRequest.serialize(UserRequest.java:166) 
    at hudson.remoting.UserRequest.<init>(UserRequest.java:62) 
    at hudson.remoting.Channel.call(Channel.java:671) 
    at hudson.FilePath.act(FilePath.java:893) 
    ... 11 more 
Caused by: java.io.NotSerializableException: java.io.PrintStream 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164) 
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518) 
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483) 
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400) 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158) 
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518) 
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483) 
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400) 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158) 
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518) 
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483) 
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400) 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158) 
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330) 
    at hudson.remoting.UserRequest._serialize(UserRequest.java:155) 
    at hudson.remoting.UserRequest.serialize(UserRequest.java:164) 
    ... 14 more 

我在做什麼錯?

鏈接:

回答

8

你傳遞一個匿名內部類act(...)它有它的父類,MyBuilder的隱式引用。我的猜測是,儘管MyBuilder實現了Serializable,但由於某些參考不是Serializable(例如java.io.PrintStream,因爲堆棧跟蹤指示),所以它實際上不能被序列化。

讓您的FileCallable<String>一個靜態內部類的實例擺脫了隱式引用其父的:

private static class MyFileCallable implements FileCallable<String> { 
    private static final long serialVersionUID = 1L; 
    @Override 
    public String invoke(File file, VirtualChannel channel) throws IOException, InterruptedException { 
    if (file.getAbsoluteFile().exists()){ 
     return file.getName() + " exists."; 
    } else { 
     return file.getName() + " doesn't exist."; 
    } 
    } 
} 

,然後用它來代替:

String result = fp.act(new MyFileCallable()); 

更新: 這裏的一個鏈接到Java的Nested Classes教程,它概述了內部類的一個實例和它的封閉外部類實例之間的關係:

的將InnerClass實例只能在 在OuterClass的實例存在,並且具有到所述方法和它的 外圍實例的字段的直接訪問。

這也在JLS(§8.1.3 Inner Classes and Enclosing Instances)的更多技術術語中解釋。

考慮到這一點,從Serializable doc這句話解釋了爲什麼你遇到的NotSerializableException

當遍歷一個圖形,對象可能會遇到不支持 Serializable接口。在這種情況下,將拋出NotSerializableException,並將標識不可序列化對象的類 。

+0

那就是那個......非常感謝。在我獎賞你的賞金之前,你能否指出我正式的文件來解釋這種微妙之處?我找不到要告訴Google的內容! –

+0

@StéphaneBruckert很高興能幫到你!更新我的答案與其他參考。 – DannyMo

+1

偉大的職位。享受這個+125! –