JavaFX: integrating Spring framework with JavaFX application (misconfiguration)

I am working on a JavaFX application and I would like to integrate Spring features with it. Currently, the code compiles without any error, but when I ask for the service layer methods that are marked @Transactional and @Service, I get a NullPointerException. What I am doing wrong in Spring configuration is what I do not understand. Here is my code for JavaFX:

Main class:

public class Main extends Application {

    private static final SpringFxmlLoader loader = new SpringFxmlLoader();

    @Override
    public void start(Stage stage) throws Exception {
       Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("login.fxml"));
        stage.setTitle("APPNAME");
        stage.setScene(new Scene(root, 300, 600));
        stage.setFullScreen(false);
        stage.setMaximized(false);
        stage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }

}


@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = {"packagename"})
public class ApplicationConfiguration {


    @Bean
    public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
        Properties properties = new Properties();
        propertySourcesPlaceholderConfigurer.setProperties(properties);
        return propertySourcesPlaceholderConfigurer;
    }

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasenames("messages", "org.springframework.security.messages");
        messageSource.setUseCodeAsDefaultMessage(true);
        return messageSource;
    }
}

      

SpringLoader:

public class SpringFxmlLoader {

    private static final ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);

    public Object load(String url) {
        try (InputStream fxmlStream = SpringFxmlLoader.class
                .getResourceAsStream(url)) {
            System.err.println(SpringFxmlLoader.class
                    .getResourceAsStream(url));
            FXMLLoader loader = new FXMLLoader();
            loader.setControllerFactory(new Callback<Class<?>, Object>() {
                @Override
                public Object call(Class<?> clazz) {
                    return applicationContext.getBean(clazz);
                }
            });
            return loader.load(fxmlStream);
        } catch (IOException ioException) {
            throw new RuntimeException(ioException);
        }
    }
}

      

Now in my controller I have something like this:

@Component
public class Controller implements Initializable {
 @FXML
    public TextField usernameField;
    @FXML
    public PasswordField passwordField;
    @FXML
    public Button submitButton;
@Autowired
    private PersonService personService;
// Now the above personService throws me a NPE.
}

      

I was messing around with Spring config for JavaFX somehow. Please let me know. Many thanks.: -)

Update

After the changes suggested by James D..I, you get the following error:

null
Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$152(LauncherImpl.java:182)
    at com.sun.javafx.application.LauncherImpl$$Lambda$2/1058634310.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException: inputStream is null.
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2459)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2429)
    at tooltank.MainClass.SpringFxmlLoader.load(SpringFxmlLoader.java:28)
    at tooltank.MainClass.Main.start(Main.java:15)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$159(LauncherImpl.java:863)
    at com.sun.javafx.application.LauncherImpl$$Lambda$57/667705538.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$172(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl$$Lambda$53/767743416.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$null$170(PlatformImpl.java:295)
    at com.sun.javafx.application.PlatformImpl$$Lambda$55/1195477817.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$171(PlatformImpl.java:294)
    at com.sun.javafx.application.PlatformImpl$$Lambda$54/1403425489.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$48(GtkApplication.java:139)
    at com.sun.glass.ui.gtk.GtkApplication$$Lambda$43/1429486634.run(Unknown Source)
    ... 1 more

Process finished with exit code 1

      

This happens in SpringFXMLLoader.java on the following line:

 return loader.load(fxmlStream);

      

0


source to share


1 answer


You have created SpringFxmlLoader

, but you are not using it. Do you want to

SpringFxmlLoader loader = new SpringFxmlLoader();
Parent root = (Parent) loader.load(getClass().getResource("login.fxml").toExternalForm());

      

instead of using it directly FXMLLoader

.

I would actually write it SpringFxmlLoader

differently, so it compares the standard API a FXMLLoader

little closer:



public class SpringFxmlLoader {

    private static final ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);

    public <T> T load(URL url) {
        try  {
            FXMLLoader loader = new FXMLLoader(url);
            loader.setControllerFactory(applicationContext::getBean);
            return loader.load();
        } catch (IOException ioException) {
            throw new RuntimeException(ioException);
        }
    }
}

      

Then your startup method looks like this:

SpringFxmlLoader loader = new SpringFxmlLoader();
Parent root = loader.load(getClass().getResource("login.fxml"));

      

You may have to work with the exact path to get it right, depending on your setup.

+2


source







All Articles