How to fix this AWT-EventQueue-0 exception

186 Views Asked by At

I write a Library login page with Java Swing and try to run it. The page can run properly but when I type in any username, choose a type and press login, it raises an AWT-EventQueue-0: NullPointerException.

The Library class deserializes two files containing the user and book info, and initialize them into objects.

User is the parent class of Member and Staff, Book class represents a book with its title, description, copy. The methods of these classes are all correct.

LoginWindow.java

import java.awt.EventQueue;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class LoginWindow {

    private JFrame frmLogIn;
    private JTextField textField;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    LoginWindow window = new LoginWindow();
                    window.frmLogIn.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Initialize the contents of the frame.
     */
    public LoginWindow() {

        frmLogIn = new JFrame();

        JLabel lblName = new JLabel("Name:");
        lblName.setBounds(23, 25, 46, 14);
        frmLogIn.getContentPane().add(lblName);

        JLabel lblType = new JLabel("Type:");
        lblType.setBounds(23, 56, 46, 14);
        frmLogIn.getContentPane().add(lblType);

        JTextField textField = new JTextField();
        textField.setBounds(71, 22, 158, 20);
        frmLogIn.getContentPane().add(textField);
        textField.setColumns(10);

        JComboBox comboBox = new JComboBox();
        comboBox.setModel(new DefaultComboBoxModel(new String[] {"Staff", "Member"}));
        comboBox.setBounds(71, 53, 158, 20);
        frmLogIn.getContentPane().add(comboBox);

        JButton btnNewButton = new JButton("Login");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {

                if (!Library.users.containsKey(textField.getText())) {
                    new CreateUserWindow();
                    frmLogIn.dispose();
                }

                else if (!Library.users.get(textField.getText()).getUserType().equals(comboBox.getActionCommand())) {
                    JOptionPane.showMessageDialog(null,
                            "The user name and user type do not match, please try again.",
                            "User information mismatch", JOptionPane.ERROR_MESSAGE);
                }

                else {
                    String type = comboBox.getActionCommand();
                    if (type.equals("Staff")) new StaffWindow((Staff)Library.users.get(textField.getText()));
                    else new MemberWindow((Member)Library.users.get(textField.getText()));
                }
            }
        });
        btnNewButton.setBounds(23, 88, 206, 23);
        frmLogIn.getContentPane().add(btnNewButton);


        frmLogIn.setTitle("Log in");
        frmLogIn.setBounds(100, 100, 268, 185);
        frmLogIn.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmLogIn.getContentPane().setLayout(null);
        frmLogIn.setVisible(true);
    }
}

Library.java

import java.io.*;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class Library implements Serializable{

    public static HashMap<String, User> users;
    public static HashMap<String, Book> books;

    public Library(boolean readFromSerialized) throws IOException, ClassNotFoundException {
        users = new HashMap<>();
        books = new HashMap<>();

        if (readFromSerialized) {
            ObjectInputStream u_in = new ObjectInputStream(new FileInputStream("./Assignment/data/Users.txt"));
            ObjectInputStream b_in = new ObjectInputStream(new FileInputStream("./Assignment/data/Books.txt"));

            users = (HashMap<String, User>) u_in.readObject();
            books = (HashMap<String, Book>) b_in.readObject();

            u_in.close();
            b_in.close();
        }
    }

    public static void serializeToFile() {
        try {
            ObjectOutputStream u_out = new ObjectOutputStream(new FileOutputStream("./Assignment/data/Users.txt"));
            ObjectOutputStream b_out = new ObjectOutputStream(new FileOutputStream("./Assignment/data/Books.txt"));

            u_out.writeObject(Library.users);
            b_out.writeObject(Library.books);

            u_out.close();
            b_out.close();
        } catch (Exception ex) {}
    }
}

Error message shows that the following code snippet contains some error, the code is about user info validation:

if (!Library.users.containsKey(textField.getText())) {
                    new CreateUserWindow();
                    frmLogIn.dispose();
                }
1

There are 1 best solutions below

2
Frakcool On

You have several issues in your code:

  1. Use of setBounds and use of null-layout (setLayout(null)), which is evil and frowned upon, as it might lead to annoying issues such as this, use proper Layout Managers in order to make your application to render correctly in all OS and PLAFs.

  2. Use of public static members, this might lead to inconsistencies in your application flow.

  3. Now, your issue is that you create a global textfield variable but never initialize it (so it's null)

    private JTextField textField;
    

    But then, on your constructor you create another one with the same name, but it's a local variable:

    JTextField textField = new JTextField();
    

    And when you call this line:

    else if (!Library.users.get(textField.getText()).getUserType().equals(comboBox.getActionCommand())) {
    

    Java is using the global variable (which remember it's null), not the local one (which is initialized), in order to fix this, remove JTextField on the declaration of the local variable:

    JTextField textField = new JTextField();
    

    So, it becomes:

    textField = new JTextField();
    

    That's going to initialize the global variable and you will be able to use it in your ActionListener