Search code examples
javaswingrecursionstack-overflow

java getting stack overflow-program is not recursive


I have been working on my "Random Trivia" program and I keep getting stack overflow with NO recursiveness, at least I cannot find any, here is the code to Gui.java, the main class(and only class)

package mods.giantnuker.random_trivia;

import java.awt.event.ActionEvent;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;

import mods.giantnuker.javautil.FileFilterAccessor;
import mods.giantnuker.javautil.Pair;
import mods.giantnuker.javautil.PairList;
import mods.giantnuker.javautil.file.parser.XMLParser;

import javax.swing.JFileChooser;

@SuppressWarnings("serial")
public class Gui extends JFrame implements ActionListener, ItemListener {
    String tsn;
    JFileChooser dialg;
    JPanel welcome, newt;
    JButton sbttn, nbttn, ebttn, nqb, nab, dqb, dab, sav, ext;
    @SuppressWarnings("rawtypes")
    JComboBox questions, answers;
    List<Pair<String, PairList<String, Integer>>> trivia;
    public static void main(String[] args) {
        new Gui();
    }
    @SuppressWarnings({ "static-access", "rawtypes" })
    public Gui() {
        super("Random Trivia");
        this.setSize(300, 250);
        this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
        //New
        newt = new JPanel();
        newt.setLayout(new BoxLayout(newt, BoxLayout.Y_AXIS));
        questions = new JComboBox();
        questions.addItemListener(this);
        answers = new JComboBox();
        nqb = new JButton("New Question+   ");
        nab = new JButton("New Answer+     ");
        dqb = new JButton("-Delete Question");
        dab = new JButton("-Delete Answer  ");
        sav = new JButton("*Save                    ");
        ext = new JButton("-Exit-                     ");
        nqb.addActionListener(this);
        nab.addActionListener(this);
        dqb.addActionListener(this);
        dab.addActionListener(this);
        sav.addActionListener(this);
        ext.addActionListener(this);
        newt.add(questions);
        newt.add(answers);
        newt.add(nqb);
        newt.add(nab);
        newt.add(dqb);
        newt.add(dab);
        newt.add(sav);
        newt.add(ext);
        //Welcome
        welcome = new JPanel();
        welcome.setLayout(new BoxLayout(welcome, BoxLayout.Y_AXIS));
        welcome.add(new JLabel("Welcome To Random Trivia!"));
        welcome.add(sbttn = new JButton("Select a file(.trv) to use"));
        welcome.add(nbttn = new JButton("Create a new one"));
        welcome.add(ebttn = new JButton("Or edit an old one"));
        sbttn.addActionListener(this);
        nbttn.addActionListener(this);
        ebttn.addActionListener(this);
        dialg = new JFileChooser();
        dialg.setDialogType(dialg.OPEN_DIALOG);
        dialg.setFileFilter(new FileFilterAccessor("trv"));
        this.add(welcome);
        this.setVisible(true);
    }
    @SuppressWarnings({ "unchecked", "rawtypes", "static-access" })
    @Override
    public void actionPerformed(ActionEvent arg0) {
        Object src = arg0.getSource();
        if (src == sbttn) {
            dialg.setDialogType(dialg.OPEN_DIALOG);
            List<Map<String, Integer>> trivia = new ArrayList();
            int out = dialg.showOpenDialog(null);
            if(out == 0) {
                File f = dialg.getSelectedFile();
            }
        }
        if (src == nbttn) {
            trivia = new ArrayList();
            this.remove(welcome);
            this.add(newt);
            this.setVisible(true);
        }
        if (src == ebttn) {
            dialg.setDialogType(dialg.OPEN_DIALOG);
            int out = dialg.showOpenDialog(null);
            if(out == 0) {
                trivia = parse(dialg.getSelectedFile());
                this.remove(welcome);
                this.add(newt);
                ref();
                this.setVisible(true);
            }
        }
        if (src == ext) {
            this.remove(newt);
            this.add(welcome);
            this.setVisible(true);
        }
        if (src == nqb) {
            String txt = JOptionPane.showInputDialog(this ,"Enter the Question:", "Question...");
            if (txt.length() > 0 && !txt.equals("Question...")) {
                trivia.add(new Pair(txt, new PairList()));
                questions.addItem(txt);
            }
        }
        if (src == nab) {
            if (questions.getItemCount() == 0) {
                JOptionPane.showMessageDialog(this, "You must select a question or create one!", "Error", JOptionPane.WARNING_MESSAGE);
                return;
            }
            String txt = JOptionPane.showInputDialog(this ,"Enter the Answer:", "Answer...");
            String txt2 = JOptionPane.showInputDialog(this ,"Enter the amount of points for the Answer:", "Points...");
            if (txt.length() > 0 && !txt.equals("Answer...")) {
                if (txt2.length() > 0 && !txt2.equals("Points...")) {
                    int points = 0;
                    boolean err = true;
                    while(err) {
                        try {
                            points = Integer.valueOf(txt2);
                            err = false;
                        } catch (NumberFormatException e) {
                            txt2 = JOptionPane.showInputDialog(this ,"Enter the amount of points for the Answer:", "Points...");
                            if (txt2.equals("Points...")) return;
                        }
                    }
                    trivia.get(questions.getSelectedIndex()).getB().add(txt, points);
                    answers.addItem(txt + "(" + points + " points)");
                }
            }
        }
        if (src == dab) {
            if (questions.getItemCount() == 0) {
                JOptionPane.showMessageDialog(this, "You must select a question!", "Error", JOptionPane.WARNING_MESSAGE);
                return;
            }
            if (answers.getItemCount() != 0) {
                trivia.get(questions.getSelectedIndex()).getB().remove(answers.getSelectedIndex());
                answers.removeItemAt(answers.getSelectedIndex());
            }
        }
        if (src == dqb) {
            if (questions.getItemCount() != 0) {
                trivia.remove(trivia.get(questions.getSelectedIndex()));
                questions.removeItemAt(questions.getSelectedIndex());
                ref();
            }
        }
        if (src == sav) {
            tsn = JOptionPane.showInputDialog(this ,"Enter the name of the Trivia:", "Name...");
            if (!tsn.equals("Name...")) newTriviaSave();
        }
    }

    @SuppressWarnings("static-access")
    public void newTriviaSave() {
        dialg.setDialogType(dialg.SAVE_DIALOG);
        int out = dialg.showSaveDialog(null);
        if(out == 0) {
            File f = dialg.getSelectedFile();
            if (!f.getPath().contains(".")) {
                f = new File(f.getPath() + ".trv");
            }
            System.out.println(f.getPath());
            toFile(f, trivia, tsn);
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public List<Pair<String, PairList<String, Integer>>> parse(File f) {
        List<Pair<String, PairList<String, Integer>>> trivia = new ArrayList();
        XMLParser p = new XMLParser(f);
        try {
            p.read();
            p.doc.getDocumentElement().normalize();
            NodeList l = p.doc.getElementsByTagName("trivia");
            Element root = (Element) l.item(0);
            tsn = root.getAttribute("name");
            l = root.getElementsByTagName("question");
            for (int i = 0; i < l.getLength(); i++) {
                Element question = (Element)l.item(i);
                NodeList l2 = question.getElementsByTagName("answer");
                PairList<String, Integer> answers = new PairList();
                for (int j = 0; j < l2.getLength(); j++) {
                    Element answer = (Element)l2.item(j);
                    answers.add(answer.getAttribute("text"), Integer.valueOf(answer.getAttribute("points")));
                }
                trivia.add(new Pair(question.getAttribute("text"), answers));
            }
        } catch (Exception e) {

        }
        return trivia;
    }

    public void toFile(File f, List<Pair<String, PairList<String, Integer>>> questions, String name) {
        XMLParser p = new XMLParser(f);
        try {
            p.create();
            Element root = p.doc.createElement("trivia");
            root.setAttribute("name", name);
            for (Pair<String, PairList<String, Integer>> question : questions) {
                Element questionE = p.doc.createElement("question");
                questionE.setAttribute("text", question.getA());
                for (Pair<String, Integer> answer : question.getB()) {
                    Element answerE = p.doc.createElement("answer");
                    answerE.setAttribute("text", answer.getA());
                    answerE.setAttribute("points", String.valueOf(answer.getB()));
                    questionE.appendChild(answerE);
                }
                root.appendChild(questionE);
            }
            p.doc.appendChild(root);
            p.write();
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (TransformerFactoryConfigurationError e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (TransformerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    @Override
    public void itemStateChanged(ItemEvent arg0) {
        Object src = arg0.getSource();
        if (src == questions) {
            ref();
        }
    }

    @SuppressWarnings("unchecked")
    public void ref() {
        questions.removeAllItems();
        answers.removeAllItems();
        for (Pair<String, PairList<String, Integer>> p : trivia) {
            questions.addItem(p.getA());
        }
        if (questions.getItemCount() != 0) {
            PairList<String, Integer> answes = trivia.get(questions.getSelectedIndex()).getB();
            for (Pair<String, Integer> ans : answes) {
                answers.addItem(ans.getA() + "(" + ans.getB() + " points)");
            }
        }
    }
}

JavaUtil works fine - not related to it.

Here is a runnable jar with JavaUtil prepackaged. to get my error, click on "edit an old one" and open the following file(just a dummy file, you could make your own and get the same result)

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<trivia name="Dummy Trivia">
    <question text="dum">
        <answer points="1" text="ans1"/>
    </question><question text="dum2">
        <answer points="1" text="ans1"/>
        <answer points="2" text="ans2"/>
    </question>
    <question text="dum3">
        <answer points="1" text="ans1"/>
        <answer points="2" text="ans2"/>
        <answer points="3" text="ans3"/>
    </question>
</trivia>

Thank you :)

EDIT: Stack overflow is in ref() \ stands for refresh

Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
    at javax.swing.plaf.basic.BasicComboBoxUI$Handler.contentsChanged(BasicComboBoxUI.java:1858)
    at javax.swing.plaf.basic.BasicComboBoxUI$Handler.intervalRemoved(BasicComboBoxUI.java:1877)
    at javax.swing.AbstractListModel.fireIntervalRemoved(AbstractListModel.java:179)
    at javax.swing.DefaultComboBoxModel.removeAllElements(DefaultComboBoxModel.java:174)
    at javax.swing.JComboBox.removeAllItems(JComboBox.java:771)
    at mods.giantnuker.random_trivia.Gui.ref(Gui.java:264)
    at mods.giantnuker.random_trivia.Gui.itemStateChanged(Gui.java:258)
    at javax.swing.JComboBox.fireItemStateChanged(JComboBox.java:1223)
    at javax.swing.JComboBox.selectedItemChanged(JComboBox.java:1280)
    at javax.swing.JComboBox.contentsChanged(JComboBox.java:1329)
    at javax.swing.AbstractListModel.fireContentsChanged(AbstractListModel.java:118)
    at javax.swing.DefaultComboBoxModel.setSelectedItem(DefaultComboBoxModel.java:93)
    at javax.swing.DefaultComboBoxModel.addElement(DefaultComboBoxModel.java:131)
    at javax.swing.JComboBox.addItem(JComboBox.java:716)
    at mods.giantnuker.random_trivia.Gui.ref(Gui.java:267)
    at mods.giantnuker.random_trivia.Gui.itemStateChanged(Gui.java:258)
    at javax.swing.JComboBox.fireItemStateChanged(JComboBox.java:1223)
    at javax.swing.JComboBox.selectedItemChanged(JComboBox.java:1271)
    at javax.swing.JComboBox.contentsChanged(JComboBox.java:1329)
    at javax.swing.JComboBox.intervalRemoved(JComboBox.java:1351)
    at javax.swing.AbstractListModel.fireIntervalRemoved(AbstractListModel.java:179)
    at javax.swing.DefaultComboBoxModel.removeAllElements(DefaultComboBoxModel.java:174)
    at javax.swing.JComboBox.removeAllItems(JComboBox.java:771)
    at mods.giantnuker.random_trivia.Gui.ref(Gui.java:264)
    at mods.giantnuker.random_trivia.Gui.itemStateChanged(Gui.java:258)
    at javax.swing.JComboBox.fireItemStateChanged(JComboBox.java:1223)
    at javax.swing.JComboBox.selectedItemChanged(JComboBox.java:1280)
    at javax.swing.JComboBox.contentsChanged(JComboBox.java:1329)
    at javax.swing.AbstractListModel.fireContentsChanged(AbstractListModel.java:118)
    at javax.swing.DefaultComboBoxModel.setSelectedItem(DefaultComboBoxModel.java:93)
    at javax.swing.DefaultComboBoxModel.addElement(DefaultComboBoxModel.java:131)
    at javax.swing.JComboBox.addItem(JComboBox.java:716)
    at mods.giantnuker.random_trivia.Gui.ref(Gui.java:267)

Continuing...


Solution

  • Looking at your stack trace, we see a problem centered on the ref() method and removing components from a JComboBox.

    There appears to be a problem here:

    @Override
    public void itemStateChanged(ItemEvent arg0) {
        Object src = arg0.getSource();
        if (src == questions) {
            ref();
        }
    }
    
    @SuppressWarnings("unchecked")
    public void ref() {
        questions.removeAllItems();
        answers.removeAllItems();
    
        ...
    

    Your ItemListener, (this -- which has been added to both questions and answers JComboBoxes) calls the ref() method which changes the state of both JComboBoxs, which triggers the ItemListener, which calls the ref() method ..... ad infinitum.

    Don't change the state of an object from within one of its listeners, or if you absolutely need to do this, then inactivate or remove the listeners first, and then re-add them. e.g.,

    public void ref() {
        // first remove all item listeners
        ItemListener[] questionListeners = questions.getItemListeners();
        ItemListener[] answerListeners = answers.getItemListeners();
    
        for (ItemListener l : questionListeners) {
            questions.removeItemListener(l);
        }
        for (ItemListener l : answerListeners) {
            answers.removeItemListener(l);
        }
    
        // change state
        questions.removeAllItems();
        answers.removeAllItems();
    
        // re-add all listeners
        for (ItemListener l : questionListeners) {
            questions.addItemListener(l);
        }
        for (ItemListener l : answerListeners) {
            answers.addItemListener(l);
        }
    
        ...