1

Introduction

I am learning Java and JavaFX and in order to do that I am working on a little project which objective is to behave as password generator.

Basically, I have 2 windows, the first one allows the user to chose what kind of password he wants. Once he is done with that, the password is generated and it should be displayed on the second window.

What is particular here is that I decided to try out the procedural and declarative for coding the windows. Which means that the windows generating the password is coded in a java file. A contrario, the window that displays the password is declared in a FXML file.

What I struggle to do is to pass the generated password to the second window. I tried many things (bad things like using static methods) and I thought about trying to use bindings (that I only recently discovered).

But this last option didn't help either as I still get the same error all the time : a null pointer exception. It is coming from the line where the password is generated by the model and the obtained String is bound to a value in the controller of the seconde view.

I am kind of stuck here and I am thinking that mixing up 2 different ways to code my views isn't the best method. Still, maybe am I not doing the binding correctly, that's what I think and hope the most.


The code

So the controller of my first view looks like this (generating the password) :

public class GeneratePasswordController implements EventHandler<MouseEvent>{

  @FXML private displayPasswordController displayPasswordController;

  @Override
  public void handle(MouseEvent event) {
    //Doing some stuff that works, then generating the password and null pointer exception occurs here
    //The method getNewPassword() returns a String (the password).
    //The model is accessed statically (an instance has been created in the Application file (Main.java)).
    displayPasswordController.pwdValueProperty().bind(Bindings.createStringBinding(()
                                          -> Main.myModel.getNewPassword()));
  }
}

And the controller of the view that displays the password :

public class NewPswdController {
  @FXML private TextField displayPassword;

  private final StringProperty pwdValue = new SimpleStringProperty("Password");

  public StringProperty pwdValueProperty() {
    return pwdValue;
  }

  public String getPwdValue() {
    return pwdValue.get();
  }

  public void setPwdValue(String value) {
    this.pwdValue.set(value);
  }

  @FXML
  void initialize() {
    dispPassword.textProperty().bind(Bindings.format("%s", pwdValue));
  }
}

The null pointer exception appears at the specific line in the controller of the view that generates the password where the model actually generates it. I am giving it, I guess it should help the most, but I couldn't really use that information untill now:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at s03.GeneratePasswordController.handle(GeneratePasswordController.java:61)
at s03.GeneratePasswordController.handle(GeneratePasswordController.java:1)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Scene$MouseHandler.process(Unknown Source)
at javafx.scene.Scene$MouseHandler.access$1500(Unknown Source)
at javafx.scene.Scene.impl_processMouseEvent(Unknown Source)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$350(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$271/1952832519.get(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.notifyMouse(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(Unknown Source)
at com.sun.glass.ui.win.WinApplication$$Lambda$36/1232367853.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Thank you for looking into it. I might learn something new there I guess, but it seems that I can't find it out by myself and it is driving me nuts since a couple of days now.

If it appears that more information is needed, I can provide more. I included everything I think is necessary.

ySiggen
  • 503
  • 1
  • 8
  • 23
  • 1
    Few points to clearify: 1) Are displayPasswordController and newPswdController the same? 2) How are you annotated the NewPswdController newPswdController with @FXML, is newPswdController nested controller or custom component? 3) IMO here you don't need to use bindings. You are not going to observe the changed password value instantly, aren't you? After the window is popped up, user will select some value then clicks "done" button where you will get the values user selected. You may search SO for "communication, data transfer, access data between two controllers" to see the similar use cases. – Uluk Biy May 18 '15 at 07:07
  • @UlukBiy 1) Yes they are the same, I edited my question (I did some poorly name choosing I guess). 2)This controller is annoted @FXML because I linked it to my FXML file (corresponding to the view that display the password) like this : `fx:controller="my Controller"` 3) Well no, what happens is when the password is generated, I also load and show the next view (by changing the scene of the stage). The password is being shown in a TextField. I am going to look into your proposals, thank's. – ySiggen May 18 '15 at 07:21
  • @UlukBiy thank's a lot, your proposal to search other use cases to access data between controllers did the trick as I found a solution that works perfectly and isn't event difficult. I found why I had a null pointer, because if a controller is linked to the FXML file you can't mess with this controller in any way you want, there is a specific one that is get the controller with a FXML loader. – ySiggen May 18 '15 at 07:43
  • 1
    Yep, the fx:controller attribute is an instruction for FXMLLoader and has nothing to do with @FXML. Glad to be helped. You may post an answer with your solution and probably put a link the Q&A you have benefited as a credit. – Uluk Biy May 18 '15 at 07:49
  • Thank's, I learned something new there! – ySiggen May 18 '15 at 07:55

1 Answers1

1

The trouble was coming from the controller that displays the password. The null pointer was most likely coming from the fact that there was no instance of that controller.

What is wrong is the part where I include the controller that displays the password using the @FXML annotation.

The following code, in the controller that generates the password, works just fine :

try {
  //Load the view and controller
  FXMLLoader loader = new FXMLLoader(getClass().getResource("displayPassword.fxml"));
  Parent displayPassword = (Parent)loader.load();
  Scene displayPasswordScene = new Scene(displayPassword);
  displayPasswordController controller = loader.getController();
  //Generate the password and set it
  controller.setPwdValue(Pastis.model.getNewPassword());
  //Load the new view on the stage
  Main.getStage().setScene(displayPasswordScene);
  Main.getStage().show();      
} catch (IOException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}

I found the answer on this question : FXMLLoader getController returns NULL?.

Community
  • 1
  • 1
ySiggen
  • 503
  • 1
  • 8
  • 23