Интеграция Spring с классом JavaFX Service приводит к сбою Service - PullRequest
0 голосов
/ 28 апреля 2018

Фон

Я работаю над приложением JavaFX для автоматического управления, редактирования и перемещения файлов в соответствии с моими предпочтениями. В конечном счете, приложение будет иметь довольно много задач, которые потребуют серьезной обработки. Я хотел бы, чтобы в нижней части экрана отображалась одна панель задач, которую можно использовать и отображать для каждой задачи, когда она запущена и скрыта в противном случае.

В связи с тем, что задачи могут занимать довольно много времени, я хотел бы также, чтобы рядом с индикатором выполнения отображался значок отмены задачи, который также может быть универсальным и отменять выполнение любой задачи, выполняемой в данный момент при нажатии.


Процесс моей мысли

Чтобы достичь этого, лучшее, что я придумала, - это создать уникальный класс, расширяющий Задачу, для каждой задачи, которую будет иметь мое приложение, этот класс будет обычным (не бин).

Затем также создайте уникальный класс, расширяющий Service для каждой из этих задач, затем в пределах класса обслуживания переопределенный метод createTask () вернет новый экземпляр соответствующей Задачи. Однако этот класс обслуживания будет подпружиненным компонентом и поэтому может быть автоматически подключен к любому классу контроллера, который должен использовать службу для запуска задачи.


Проблема

Когда я нажимаю кнопку, которая в конечном итоге запускает службу, служба завершается сбоем и переводится в состояние СБОЙ. Когда я смотрю на отладчик, кажется, что исключение происходит из-за исключения нулевого указателя из-за того, что контроллер файлового браузера имеет значение null. Однако контроллер файлового браузера должен получать Autowired в классе задач, когда он создается методом service createTask ().

Я не уверен на 100%, что это является причиной проблемы, поскольку отладка службы оказалась немного сложной, но кажется, что это так, потому что это исключение, которое установлено в значение Задача прямо перед для службы установлено значение «Сбой»


Код

Класс контроллера (запускает обслуживание)

@Component
public class FileBrowserController implements Initializable {

    @Autowired
    private GetSelectedFilesCountService getSelectedFilesCountService;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // Code to build the file browser tree
    }


     /*******************************************************************************************************
     ***************************               BUTTON FUNCTIONALITY               ***************************                                       
     *        Gets the total count of leaf files from the users selection in the File Browser window        *
     ********************************************************************************************************/

    @FXML
    private void handleButtonAction(ActionEvent event) {

        // Initially set value to 0 and then bind the value with the service value property, 
        // which ultimately gets its value form the GetSelectedFilesCountTask 
        ObjectProperty<Integer> fileCount = new SimpleObjectProperty<Integer>(0);
        fileCount.bind(getSelectedFilesCountService.valueProperty());


        // On success print the value to the screen to check that this is working properly
        getSelectedFilesCountService.setOnSucceeded(new EventHandler<WorkerStateEvent>() {

            @Override
            public void handle(WorkerStateEvent event) {
                System.out.println("The Service was successful, file count: " + fileCount.get());
            }
        });

        if(getSelectedFilesCountService.getState() == Service.State.READY) {
            getSelectedFilesCountService.start();
        }
        else if(getSelectedFilesCountService.getState() != Service.State.RUNNING 
                || getSelectedFilesCountService.getState() != Service.State.SCHEDULED) {
            getSelectedFilesCountService.reset();
            getSelectedFilesCountService.start();
        }
    }
}


Класс обслуживания (создает и возвращает новый экземпляр задачи)

@Component
public class GetSelectedFilesCountService extends Service<Integer> {

    @Override
    protected Task<Integer> createTask() {
        return new GetSelectedFilesCountTask();
    }   
}


Task Class, выполняет актуальную задачу

@Component
public class GetSelectedFilesCountTask extends Task<Integer> {

    @Autowired
    private FileBrowserController fileBrowserController;

    private Integer leafCount;

    @Override
    protected Integer call() {
        leafCount = 0;
        getSelectedItemsCount(fileBrowserController.getFileBrowser().getSelectionModel().getSelectedItems());
        return leafCount;
    }

    /*****************************************************************
     *Recursively counts the leaves within a single or group of Files 
     *****************************************************************/
    private void getSelectedItemsCount(List<TreeItem<File>> files) {

        for(TreeItem<File> f : files) {
            if(f.isLeaf()) {
                leafCount++;
            }else {
                getSelectedItemsLeafCount(f.getChildren());
            }
        }
    }

    @Override
    protected void cancelled() {
        updateMessage("Operation Cancelled");
    }
}


Spring Config File

@Configuration
public class SpringAppConfig {

    @Bean
    public DataModel datamodel() {
        return new DataModel();
    }

    @Bean
    public GetSelectedFilesCountService getSelectedFilesCountService() {
        return new GetSelectedFilesCountService();
    }
}



Решения, которые я попробовал

Первоначально я хотел также объявить Задачи как прототипы пружинных компонентов, а затем автоматически связать их с сервисом в качестве свойств, а затем вернуть значение автосвязи в методе createTask (). Это решение сработало бы в первый раз, когда я нажал на кнопку, но затем во второй раз он сгенерирует исключение, потому что Spring создаст новый экземпляр свойства задачи только на первом проходе, а затем, когда служба будет сброшена, и задача будет установлена ​​на ноль, он никогда не будет создан снова. ниже приведен фрагмент

Служба с автоматическим заданием

@Component
public class GetSelectedFilesCountService extends Service<Integer> {

    @Autowired
    private GetSelectedFilesCountTask getSelectedFilesCountTask;

    @Override
    protected Task<Integer> createTask() {
        return getSelectedFilesCountTask;
    }   
}

После этого я решил, что, возможно, я все еще смогу выполнить вышеизложенное, создав фабрику компонентов для задач, а затем вызвав метод createBean () фабрики компонентов, чтобы вернуть новый экземпляр задачи, но в конечном итоге это не сработало. и я чувствовал, что могу сделать то же самое, просто используя сервис как фабрику для создания новых экземпляров только с половиной кода.



UPDATE

Я все еще хотел бы знать, в чем заключалась первоначальная проблема с кодом выше (возвращая новый экземпляр подкласса Task), но сейчас я нашел решение .... или обходной путь, создав и возвратив Экземпляр анонимной задачи. Я предполагаю, что это приемлемо, потому что мне не придется повторять код, потому что сервис можно использовать несколько раз, но я все равно предпочел бы иметь код в своем собственном классе. Это странно, потому что это буквально тот же самый точный код, который у меня был в подклассе Task, который продолжал давать сбой, но я предполагаю. Ниже приведен фрагмент кода на случай, если он будет полезен кому-то еще.

@Component
public class GetSelectedFilesCountService extends Service<Integer> {

    @Autowired
    private FileBrowserController fileBrowserController;

    private Integer leafCount;

    @Override
    protected Task<Integer> createTask() {

        return new Task<Integer>() {

            @Override
            protected Integer call() {
                leafCount = 0;
                getSelectedItemsLeafCount(fileBrowserController.getFileBrowser().getSelectionModel().getSelectedItems());
                return leafCount;
            }

            /*****************************************************************
             *Recursively counts the leaves within a single or group of Files 
             *****************************************************************/
            private void getSelectedItemsLeafCount(List<TreeItem<File>> files) {

                for(TreeItem<File> f : files) {
                    if(f.isLeaf()) {
                        leafCount++;
                    }else {
                        getSelectedItemsLeafCount(f.getChildren());
                    }
                }
            }
        };
    }   
}

1 Ответ

0 голосов
/ 29 апреля 2018

Не полное решение, но достойный обходной путь - использовать и возвращать анонимную задачу из метода createTask в сервисе. По какой-то причине возникает проблема, когда я пытаюсь вернуть новый экземпляр определенного подкласса Task, в котором экземпляр bean-компонента не создается, пожалуйста, прокомментируйте, если знаете, почему это так.

Решение

@Component
public class GetSelectedFilesCountService extends Service<Integer> {

    @Autowired
    private FileBrowserController fileBrowserController;

    private Integer leafCount;

    @Override
    protected Task<Integer> createTask() {

        return new Task<Integer>() {

            @Override
            protected Integer call() {
                leafCount = 0;
                getSelectedItemsLeafCount(fileBrowserController.getFileBrowser().getSelectionModel().getSelectedItems());
                return leafCount;
            }

            /*****************************************************************
             *Recursively counts the leaves within a single or group of Files 
             *****************************************************************/
            private void getSelectedItemsLeafCount(List<TreeItem<File>> files) {

                for(TreeItem<File> f : files) {
                    if(f.isLeaf()) {
                        leafCount++;
                    }else {
                        getSelectedItemsLeafCount(f.getChildren());
                    }
                }
            }
        };
    }   
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...