Why is my boolean value preemptively being returned?

123 views Asked by At

I am working on a login validator and have a class that checks username and password validity. After checking, a boolean variable (isValidLoginCredentials) is updated in the LoginProxy class, which can be fetched by a get method and used for another purpose. However, the value that is returned by the get method is always the default value that I assigned to isValidLoginCredentials when the class was created. I think the issue is that I am calling the getter method in main() before I have a chance to update isValidLoginCredentials, but I don't understand what changes I should make to stop this. Here is the relevant part of the class and main program.

public class LoginProxy implements ActionListener
{
    private JLabel usernameLabel;
    private JTextField usernameText;
    private JLabel passwordLabel;
    private JPasswordField passwordText;
    private JButton loginButton;
    private boolean isValidLoginCredentials = false;
    
    public void createLogin()
    {
        /*Here was code irrelevant to the problem I removed*/
  

        loginButton.addActionListener(new LoginProxy());
        
        loginButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e) 
            {
                String user = usernameText.getText();//get the username
                String pass = passwordText.getText();//get the password
                String credentials = user +":"+pass;//creates the string I compare to other valid 
                                                    //credentials
                
                ConcreteLoginValidator validator = new ConcreteLoginValidator(credentials);
        
                try 
                {
                    isValidLoginCredentials = validator.checkLogin();
                    System.out.println("The credentials are "+isValidLoginCredentials);
                } 
                catch (FileNotFoundException e1) 
                {
                    e1.printStackTrace();
                }
            
            }
        });
    }

    public void actionPerformed(ActionEvent e) 
    {
        // TODO Auto-generated method stub
        
    }

    public boolean getValidity()
    {
        return isValidLoginCredentials;
    }
    

And here is the main method

public static void main(String[] args) 
    {
        boolean isValidLogin = false;
        LoginProxy proxy = new LoginProxy();
        proxy.createLogin();
        isValidLogin = proxy.getValidity();
    
        if(isValidLogin == true)
        {
            JFrame frame = MainUI.getInstance();
            frame.setSize(900, 600);
            frame.pack();
            frame.setVisible(true);
        }    
    }

What should I add so that isValidLogin=proxy.getValidity(); returns a value only after I have already entered and checked whether the login credentials are correct?

3

There are 3 answers

0
leozin On BEST ANSWER

Going straight to the point, a quick fix is to put the code below:

if(isValidLoginCredentials) {
    JFrame frame = MainUI.getInstance();
    frame.setSize(900, 600);
    frame.pack();
    frame.setVisible(true);
}

After this part:

System.out.println("The credentials are "+isValidLoginCredentials);

The code you call on createLogin() just sets the action listener to the button in the UI, hence the code will be executed just when you click on the button. On the top of that, when you open a window, it starts a separated thread. I don't know the rest of the code, but assuming that when you instantiate the LoginProxy, it opens the login window. But the way you wrote, it will open the window and check the isValidLogin straight away (it doesn't wait you to click the button).

If you want to prove that, you can simply put a System.out.println before and after the proxy.createLogin(). You will realise that both lines will be reached while the UI is rendered.

1
Bohemian On

In order to guarantee reading a value written in another thread, you must make the field volatile:

private volatile boolean isValidLoginCredentials;

You must also wait until the other completes before reading it. That aspect I leave to the reader.

0
AudioBubble On

Using a modal dialog that blocks until it is closed.

Very simplified example:

public class Dialog {    // LoginProxy in questions code

    private String value = null;
    
    public void show(Window owner) {
        var dialog = new JDialog(owner, JDialog.DEFAULT_MODALITY_TYPE);
        var field = new JTextField(40);

        var okButton = new JButton("OK");
        okButton.addActionListener(ev -> {
            value = field.getText();
            dialog.dispose();
        });

        var panel = new JPanel();
        panel.add(field);
        panel.add(okButton);

        dialog.add(panel);
        dialog.pack();
        dialog.setLocationRelativeTo(owner);
        dialog.setVisible(true);  // this will be blocked until JDialog is closed
    }
    
    public String getValue() {
        return value;
    }
}

called like

    public static void main(String[] args) {
        var dialog = new Dialog();
        dialog.show(null);
        System.out.println(dialog.getValue());  // check if valid and open JFrame in questions code
    }

Advantage of this solution IMHO: the dialog class (LoginProxy) does not need to know about the main class and main JFrame. It has a clear single function: ask for user input.

the dialog creation is even easier using JOptionPane