0

I am currently developing an application that uses Spring Boot and JavaFX. I want to store email and password in H2 database. With a JUnit test I have already checked if the database is running and I have access to the Spring Boot repository. This works. However, I need to access the Spring Boot service from the JavaFX controller to be able to control the logic from the GUI and after I autowire the Spring Boot service in this class, a NullPointerException comes.

JavaFXController

@Component
@FxmlView("start.fxml")
@Service
public class JavaFXController {

    @FXML private Label startLabel;
    @FXML private Label settingsLabel;
    @FXML private TextField emailAmazonMerchOnDemand;
    @FXML private PasswordField passwordAmazonMerchOnDemand;

    private Stage stage;
    private Scene scene;

    @Autowired
    private AmazonMerchOnDemandService amazonMerchOnDemandService;

    @FXML
    public void openSettingsSceneFromStartScene() throws IOException {
        Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("settings.fxml"));
        stage = (Stage)(startLabel.getScene().getWindow());
        scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    @FXML
    public void saveLogins() {
        String emailAmazon = emailAmazonMerchOnDemand.getText();
        String passwordAmazon = passwordAmazonMerchOnDemand.getText();
        AmazonMerchOnDemand amazonMerchOnDemandLogin = new AmazonMerchOnDemand();
        amazonMerchOnDemandLogin.setId(1L);
        amazonMerchOnDemandLogin.setEmail(emailAmazon);
        amazonMerchOnDemandLogin.setPassword(passwordAmazon);
        amazonMerchOnDemandService.saveLogin(amazonMerchOnDemandLogin);
    }
}

JavaFXApplication

@SpringBootApplication
public class JavaFXApplication extends Application {
    private ConfigurableApplicationContext applicationContext;

    @Override
    public void init() throws Exception {
        String[] args = getParameters().getRaw().toArray(new String[0]);
        this.applicationContext = new SpringApplicationBuilder().sources(PrintOnDemandSellerViewApplication.class).run(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        FXMLLoader loader = new FXMLLoader();
        URL xmlUrl = getClass().getClassLoader().getResource("start.fxml");
        loader.setLocation(xmlUrl);
        loader.setController(applicationContext.getBean(JavaFXController.class));
        Parent root = loader.load();
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    @Override
    public void stop() throws Exception {
        this.applicationContext.close();
        Platform.exit();
    }
}

AmazonMerchOnDemandService

@Service
@Component
public class AmazonMerchOnDemandService {

    public static WebDriver driver;
    private static int amountOfSales;

    @Autowired
    private AmazonMerchOnDemandRepository amazonMerchOnDemandRepository;

    public void saveLogin(AmazonMerchOnDemand amazonMerchOnDemand) {
        amazonMerchOnDemandRepository.save(amazonMerchOnDemand);
    }

    public void chromeDriverSetUp() {
        System.setProperty("webdriver.chrome.driver", "C:\\Program Files (x86)\\chromedriver.exe");
        driver = new ChromeDriver();
        driver.manage().window().maximize();
    }

    public void login() {
        String email = amazonMerchOnDemandRepository.findById(1L).get().getEmail();
        System.out.println("Email: " + email);
        String password = amazonMerchOnDemandRepository.findById(1L).get().getPassword();
        System.out.println("Password: " + password);
}
}

AmazonMerchOnDemandRepository

@Repository
public interface AmazonMerchOnDemandRepository extends CrudRepository <AmazonMerchOnDemand, Long> {
}

PrintOnDemandSellerViewApplicationTests

@SpringBootTest(classes = JavaFXApplication.class)
class PrintOnDemandSellerViewApplicationTests {

    @Autowired
    private AmazonMerchOnDemandRepository amazonMerchOnDemandRepository;
    @Autowired
    private AmazonMerchOnDemandSampleData amazonMerchOnDemandSampleData;

    @BeforeEach
    public void setupData() {
        amazonMerchOnDemandSampleData.createAmazonMerchOnDemandLogin();
    }

    @Test
    public void testHasAmazonMerchOnDemandLoginRightPasswordAndRightEmail() {
        assertTrue(amazonMerchOnDemandRepository.existsById(1L));
        Optional<AmazonMerchOnDemand> amazonMerchOnDemandOptional = amazonMerchOnDemandRepository.findById(1L);
        assertFalse(amazonMerchOnDemandOptional.isEmpty());
        AmazonMerchOnDemand amazonMerchOnDemandLogin = amazonMerchOnDemandOptional.get();
        assertEquals("password", amazonMerchOnDemandLogin.getPassword());
        assertEquals("test@gmail.com", amazonMerchOnDemandLogin.getEmail());
    }

}

NullPointerException

Caused by: java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:77)
    at jdk.internal.reflect.GeneratedMethodAccessor37.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at javafx.base@19/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml@19/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:84)
    at javafx.fxml@19/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1854)
    ... 29 more
Caused by: java.lang.NullPointerException
    at com.example.printondemandsellerview.JavaFXController.saveLogins(JavaFXController.java:53)
    ... 40 more

I have tried several solutions from StackOverflow:

Dependency Injection in JavaFX Spring Data Autowire in FXML Controller

Unfortunately, none of the solutions could help me. Do you have any other suggestions as to what the problem might be?

Maik
  • 11
  • 4
  • I notice you have two FXML files. Presumably `settings.fxml` has its own controller class, and presumably since you are not setting the controller or the controller factory when you load `settings.fxml`, that controller does not need to be managed by spring. Assuming all that is true and the null pointer exception is stemming from an action in `start.fxml`, I would check that 1. you do **not** have a `fx:controller` attribute in `start.fxml`, and 2. `applicationContext.getBean(JavaFXController.class)` is not returning null. – James_D Feb 17 '23 at 14:06
  • 1
    Also note that JavaFX controller classes in DI-managed applications (such as Spring) should have `prototype` scope. If you load the same FXML twice, you should have two controller instances. – James_D Feb 17 '23 at 14:15
  • Perhaps consider [javafx-weaver](https://github.com/rgielen/javafx-weaver), rather than a custom Spring integration. I have never used the javafx-weaver library, so the link is not a recommendation, just something for you to investigate and evaluate independently. – jewelsea Feb 17 '23 at 14:51
  • I demonstrate wiring a service into a controller in [Adding Spring Dependency Injection in JavaFX (JPA Repo, Service)](https://stackoverflow.com/a/57896435/1155209). Perhaps take a look at that. – jewelsea Feb 17 '23 at 15:08
  • @James_D In the settings.fxml I also use the JavaFXController class as controller. In the start.fxml I have no fx:controller attribute. When I call applicationContext.getBean(JavaFXController.class), it does not return null. The null pointer exception occurs when I call the saveLogins() method in the GUI. There the class then accesses the repository for the first time. Because this is null, the null pointer exception occurs. – Maik Feb 20 '23 at 14:18
  • *"In the settings.fxml I also use the JavaFXController class as controller. "*. Don't do this. Each FXML should have its own controller class. Since you don't set the controller or controller factory when you load `settings.fxml`, the controller that is created when you load `settings.fxml` is not spring-managed, and so won't have any spring-injected fields initialized. – James_D Feb 20 '23 at 18:46

0 Answers0