2013-07-18 8 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()); 

Update: Вот ссылка на учебник Java Nested Classes, в котором описывается взаимосвязь между экземпляром внутреннего класса и его окружающим экземпляром внешнего класса:

Экземпляр InnerClass может существовать только внутри экземпляра OuterClass и имеет прямой доступ к методам и полям его охватывающему экземпляра.

Об этом также говорится на более технических условиях в JLS (§8.1.3 Inner Classes and Enclosing Instances).

Имея это в виду, что эта цитата из Serializable doc объясняет, почему вы столкнулись с NotSerializableException:

При перемещении графика, объект может столкнуться, что не поддержки сериализуемый интерфейса. В этом случае будет выбрано значение NotSerializableException и будет идентифицировать класс несериализуемого объекта.

+0

Это было ... спасибо. Прежде чем вручить вам награду, не могли бы вы указать мне официальный документ, объясняющий эту тонкость? Я не могу найти, что сказать Google! –

+0

@ StéphaneBruckert Рад, что я мог бы помочь! Обновленный мой ответ с дополнительными ссылками. – DannyMo

+1

Отличный пост. Наслаждайтесь этим +125! –

Смежные вопросы