2017-04-06 2 views
0

Lorsque j'appelle la méthode de connexion dans la classe LoginViewController, je reçois une exception NullPointerException. Je sais que l'objet utilisateur n'est pas nul puisqu'il imprime l'objet avec un toString. Dois-je enregistrer la classe Client et Utilisateur dans le fichier LoginView.fxml d'une manière ou d'une autre? Ce que j'essaie de réaliser, c'est que lorsque l'utilisateur clique sur la connexion, la méthode devrait instancier un nouveau client qui envoie l'objet Utilisateur au serveur.NullPointerException lors de l'appel de la méthode avec (JavaFX)

Exception

User: Username Password 
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException 
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774) 
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657) 
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) 
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) 
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49) 
    at javafx.event.Event.fireEvent(Event.java:198) 
    at javafx.scene.Node.fireEvent(Node.java:8411) 
    at javafx.scene.control.Button.fire(Button.java:185) 
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182) 
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96) 
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89) 
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218) 
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) 
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) 
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) 
    at javafx.event.Event.fireEvent(Event.java:198) 
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757) 
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485) 
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762) 
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416) 
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415) 
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555) 
    at com.sun.glass.ui.View.notifyMouse(View.java:937) 
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) 
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) 
    at java.lang.Thread.run(Unknown Source) 
Caused by: java.lang.reflect.InvocationTargetException 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
    at java.lang.reflect.Method.invoke(Unknown Source) 
    at sun.reflect.misc.Trampoline.invoke(Unknown Source) 
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
    at java.lang.reflect.Method.invoke(Unknown Source) 
    at sun.reflect.misc.MethodUtil.invoke(Unknown Source) 
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1771) 
    ... 48 more 
Caused by: java.lang.NullPointerException 
    at dinnerTime.Client.sendToServer(Client.java:44) 
    at dinnerTime.LoginViewController.login(LoginViewController.java:34) 
    ... 58 more 

Main.java

package dinnerTime; 

import java.io.IOException; 
import javafx.application.Application; 
import javafx.fxml.FXML; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Scene; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 

public class Main extends Application { 
    private Stage primaryStage; 
    private BorderPane mainLayout; 

    public static void main(String[] args) { 
     launch(args); 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     this.primaryStage = primaryStage; 
     showLoginView(); 
    } 

    private void showLoginView() throws IOException { 
     FXMLLoader loader = new FXMLLoader(); 
     loader.setLocation(Main.class.getResource("LoginView.fxml")); 
     mainLayout = loader.load(); 
     Scene scene = new Scene(mainLayout, 540, 400); 
     primaryStage.setScene(scene); 
     primaryStage.setResizable(false); 
     primaryStage.show(); 
    } 
} 

LoginViewController.java

package dinnerTime; 

import java.io.IOException; 
import java.net.URL; 
import java.util.ResourceBundle; 
import javafx.fxml.FXML; 
import javafx.fxml.Initializable; 
import javafx.scene.control.Button; 
import javafx.scene.control.PasswordField; 
import javafx.scene.control.TextField; 

public class LoginViewController { 
    @FXML 
    private Main main; 
    @FXML 
    private TextField username; 
    @FXML 
    private PasswordField password; 
    @FXML 
    private Button login; 
    @FXML 
    private Button register; 

    private Client client; 

    private User user; 

    @FXML 
    public void login() throws IOException { 
     client = new Client("127.0.0.1", 3250); 
     client.start(); 
     user = new User(username.getText(), password.getText()); 
     System.out.println("User: " + user.toString()); 
     client.sendToServer(user); 
    } 
} 

LoginView.fxml

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.control.Button?> 
<?import javafx.scene.control.Label?> 
<?import javafx.scene.control.PasswordField?> 
<?import javafx.scene.control.TextField?> 
<?import javafx.scene.image.Image?> 
<?import javafx.scene.image.ImageView?> 
<?import javafx.scene.layout.AnchorPane?> 
<?import javafx.scene.layout.BorderPane?> 
<?import javafx.scene.text.Font?> 

<BorderPane prefHeight="400.0" prefWidth="540.0" xmlns="http://javafx.com/javafx/8.0.102" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dinnerTime.LoginViewController"> 
    <center> 
     <AnchorPane prefHeight="400.0" prefWidth="540.0" BorderPane.alignment="CENTER"> 
     <children> 
      <ImageView fitHeight="122.0" fitWidth="124.0" layoutX="238.0" layoutY="14.0" pickOnBounds="true" preserveRatio="true"> 
       <image> 
        <Image url="@../../images/dt-logo-original.png" /> 
       </image> 
      </ImageView> 
      <Label layoutX="14.0" layoutY="14.0" text="Dinner" textFill="#464646"> 
       <font> 
        <Font size="70.0" /> 
       </font> 
      </Label> 
      <Label layoutX="372.0" layoutY="14.0" text="Time" textFill="#464646"> 
       <font> 
        <Font size="70.0" /> 
       </font></Label> 
      <Label layoutX="91.0" layoutY="155.0" text="Username" /> 
      <TextField layoutX="164.0" layoutY="151.0" prefHeight="25.0" prefWidth="216.0" /> 
      <Label layoutX="91.0" layoutY="213.0" text="Password" /> 
      <PasswordField layoutX="164.0" layoutY="209.0" prefHeight="25.0" prefWidth="216.0" /> 
      <Button fx:id="login" layoutX="162.0" layoutY="271.0" mnemonicParsing="false" onAction="#login" prefHeight="59.0" prefWidth="216.0" text="Login" /> 
      <Button layoutX="242.0" layoutY="352.0" mnemonicParsing="false" text="Register" /> 
     </children> 
     </AnchorPane> 
    </center> 
</BorderPane> 

Client.java

package dinnerTime; 

import java.io.*; 
import java.net.*; 

public class Client extends Thread { 
    private String ip; 
    private int port; 
    private Socket socket; 
    private ObjectOutputStream oos; 
    private ObjectInputStream ois; 

    public Client(String ip, int port) { 
     this.ip = ip; 
     this.port = port; 
    } 

    public void run() { 
     try { 
      socket = new Socket(ip, port); 
      oos = new ObjectOutputStream(socket.getOutputStream()); 
      oos.flush(); 
      ois = new ObjectInputStream(socket.getInputStream()); 

      while (true) { 
       try { 
        Object obj = ois.readObject(); 

        if (obj instanceof Recipe) { 

        } 


       } catch (IOException | ClassNotFoundException e) { 
       } 
      } 
     } catch (IOException e) { 
     } 
    } 

    public void sendToServer(Object obj) { 
     try { 
      oos.writeObject(obj); 
      oos.flush(); 
     } catch (IOException e) { 
     } 
    } 
} 

User.java

package dinnerTime; 

import java.io.Serializable; 

public class User implements Serializable { 
    private String name, password; 

    public User(String name, String password){ 
     this.name = name; 
     this.password = password; 
    } 

    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public String toString() { 
     return name + " " + password; 
    } 
} 
+1

Pourquoi vous annoter '' Client' et user' avec '@ FXML'? Ces classes ne sont pas des noeuds et ne sont pas inclus ni dans le fichier FXML ni dans le Scenegraph. –

+0

Mon mauvais, ils sont supprimés maintenant. Toujours la même exception. Des idées? – Slamdunk

Répondre

0

Vous avez un race condition sur le champ oos du client. Vous l'initialisez dans la méthode run(), qui est exécutée sur le thread d'arrière-plan, mais vous essayez d'y accéder dans sendToServer() qui est appelée à partir de login() dans le contrôleur et exécutée sur le thread d'application FX.

Parce que ceux-ci sont sur différents threads, il n'y a aucune garantie quant à qui sera exécuté en premier: ce qui se passe est que sendToServer() est CHAISE avant que le thread d'arrière-plan initialise oos, et donc oos.writeObject(...) est de lancer une exception de pointeur nul.

Pour résoudre ce problème, vous devez vous assurer que vous n'appelez pas sendToServer() tant que le client n'est pas entièrement connecté. Une approche consiste à fournir un rappel de quelque sorte à exécuter lorsque la connexion est établie:

public class Client extends Thread { 
    private String ip; 
    private int port; 
    private Socket socket; 
    private ObjectOutputStream oos; 
    private ObjectInputStream ois; 

    private Runnable onConnected ; 

    public void setOnConnected(Runnable onConnected) { 
     this.onConnected = onConnected ; 
    } 

    public Client(String ip, int port) { 
     this.ip = ip; 
     this.port = port; 
    } 

    public void run() { 
     try { 
      socket = new Socket(ip, port); 
      oos = new ObjectOutputStream(socket.getOutputStream()); 
      oos.flush(); 

      if (onConnected != null) { 
       onConnected.run(); 
      } 

      ois = new ObjectInputStream(socket.getInputStream()); 

      while (true) { 
       try { 
        Object obj = ois.readObject(); 

        if (obj instanceof Recipe) { 

        } 


       } catch (IOException | ClassNotFoundException e) { 
       } 
      } 
     } catch (IOException e) { 
     } 
    } 

    public void sendToServer(Object obj) { 
     try { 
      oos.writeObject(obj); 
      oos.flush(); 
     } catch (IOException e) { 
     } 
    } 
} 

puis

@FXML 
public void login() throws IOException { 
    client = new Client("127.0.0.1", 3250); 
    user = new User(username.getText(), password.getText()); 
    client.setOnConnected(() -> client.sendToServer(user)); 
    client.start(); 
}