Reputation: 189
Here's the error code I got:
Exception in thread "main" java.lang.StackOverflowError
at JavaKeywords.<init>(JavaKeywords.java:5)
at LAddClass.<init>(LAddClass.java:8)
at LStore.<init>(LStore.java:9)
at LAddClass.<init>(LAddClass.java:9)
at LStore.<init>(LStore.java:9)
and below is the three classes mentioned above. Sorry for posting the code of nearly the entire programme, but I really have no idea where's the error. The three lines makred by the error code are highlighted below.
This is a programme of UML-toJava converter. The user has to input class name and class type(public/ private), and have the variables stored in virtual class. I've made an ArrayList of class object to store users' input, String className and boolean isPrivate. Later the class name and type has to be printed in a GUI window for user to copy the text.
I guess the error is related to failed to store the values (String className, String classMethod, boolean isPrivate
) to the ArrayList<LStore>
which is an arrayList for objects of the LStore class. I've got a Null Pointer Exception error before, which should be related to the arraylist, and after i changed some of my codes and class names, I've got this new stackOverFlow
error.
LAddClass class
for using checkName()
and turning bolean isPrivate
to a string for later use
public class LAddClass{
private String className;
private String methodName;
private boolean isPrivate;
JavaKeywords keyObject = new JavaKeywords();
LStore stObject = new LStore(className, methodName,isPrivate);//<<<<<<<<<<<<<<<<<<<<<<<<<<< related to the error
public String getPublic(){
String s;
if (stObject.getIsPrivate() == true)
s = " private";
else
s = "public";
return s;
}
public void setPublic(){
}
public boolean checkName(String name){
boolean check = true;
for (int i=0; i<=stObject.getListSize(); i++){
if (keyObject.containsKeyword(name) || name.equals(stObject.getClassName())){
boolean o = false;
check = o;
}// end if
}// end for
return check;
}// end checkName
}//end class
the LStore class
which is a class for storing the variables to ArrayList<LStore>
import java.util.*;
public class LStore {
public static ArrayList<LStore> classes = new ArrayList<LStore>();
public boolean isPrivate;
public String className;
public String methodName;
LAddClass classObject = new LAddClass(); //<<<<<<<<<<<<<<<<<<<<<<<<<<< related to the error
public LStore(String name, String method, boolean isP){
this.className = name;
this.isPrivate = isP;
this.methodName = method;
classes.add(this);
}
public String getClassName(){
return className;
}
public String getMethodName(){
return methodName;
}
public boolean getIsPrivate(){
return isPrivate;
}
public int getListSize(){
return classes.size();
}
public String getJavaCode(){
String javaCode = (classObject.getPublic() + " " + className +"{\n"+"\t"+methodName+"\t\n}"+"}");
return javaCode;
}
}
and here the GUI class GuiAddClass
for users to create new class. I think it may contain some errors as well so I would put this on for reference.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GuiAddClass extends JFrame{
LAddClass classObject = new LAddClass();
private JRadioButton publicButton, privateButton;
private JLabel clazz;
private JTextField inputClassName;
private JLabel mothod;
private JTextField inputMethodName;
private JLabel note;
private JButton confirmButton;
private JButton cancelButton;
public GuiAddClass(){
super("Create class");
setLayout(new FlowLayout());
publicButton = new JRadioButton("public", false);
privateButton = new JRadioButton("private", true);
clazz = new JLabel("Class Name: ");
inputClassName = new JTextField("ExampleClass",10);
mothod = new JLabel("Method Name*: ");
inputMethodName = new JTextField("doSomething()",10);
note = new JLabel("*All methods are public void in default. You may only create one method for a class.");
confirmButton = new JButton("Confirm");
cancelButton = new JButton("Cancel");
add(publicButton);
add(privateButton);
add(clazz);
add(inputClassName);
add(mothod);
add(inputMethodName);
add(note);
add(confirmButton);
add(cancelButton);
ButtonGroup group = new ButtonGroup();
group.add(publicButton);
group.add(privateButton);
Handler handler = new Handler();
NewHandler newhandler = new NewHandler();
confirmButton.addActionListener(handler);
cancelButton.addActionListener(newhandler);
}// end constructor AddClass()
private class Handler implements ActionListener{
public void actionPerformed(ActionEvent event){
String cName = inputClassName.getText();
String mName = inputMethodName.getText();
boolean isP = true;
if (classObject.checkName(cName) == false){
JOptionPane.showMessageDialog(null, "Class name invalid. " +
"\nEntered name should not contain java keywords or equal to other existing names. " +
"\nPlease try again.");
} else if (classObject.checkName(cName) == true) {
JOptionPane.showMessageDialog(null, "Class saved.");
cName = inputClassName.getText();
mName = inputMethodName.getText();
if (event.getSource() == publicButton) {
isP = false;
} else if (event.getSource() == privateButton) {
isP = true;
}
new LStore(cName, mName, isP);
}
}// end actionPerformed()
}// end Handler class
private class NewHandler implements ActionListener{
public void actionPerformed(ActionEvent event){
setVisible(false);
}
}
}// end AddClass
JavaKeywords class
originally from How to check if the class name is valid?, a class with the method to check if className equals to java reserved keywords. it maybe related to the error as well, since this class seemed to be detected as error quite frequently
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
/**
* JavaKeywords is a Utility class related to the reserved keywords
*
* @author MrLore from https://stackoverflow.com/questions/13979172/how-to-check-if-the-class-name-is-valid
*/
public class JavaKeywords
{
private static final HashSet<String> keywords = new HashSet(Arrays.asList(new String[]{
//There are 50 keywords, and 3 literals; true, false and null.
"abstract", "assert", "boolean", "break", "byte",
"case", "catch", "char", "class", "const",
"continue", "default", "do", "double", "else",
"enum", "extends", "false", "final", "finally",
"float", "for", "goto", "if", "implements",
"import", "instanceof", "int", "interface", "long",
"native", "new", "null", "package", "private",
"protected", "public", "return", "short", "static",
"strictfp", "super", "switch", "synchronized", "this",
"throw", "throws", "transient", "true", "try",
"void", "volatile", "while" , "string", "int"
}));
public static boolean isKeyword(String toCheck){
return getKeywords().contains(toCheck);
}//End isKeyword()
public static String[] getAsArray(){
return getKeywords().toArray(new String[getKeywords().size()]);
}//End getAsArray()
public static ArrayList<String> getAsArrayList(){
return new ArrayList(getKeywords());
}//End getAsArrayList()
public static HashSet<String> getAsHashSet(){
return getKeywords();
}//End getAsHashSet()
public static HashSet<String> getKeywords() {
return keywords;
}//End getKeywords
public boolean containsKeyword(String toCheck){
toCheck = toCheck.toLowerCase(); //<<<<<<<<<<<<<<<<<<<<<<< this line had been detected as error of null-pointer-exception
for(String keyword : keywords){
if(toCheck.equals(keyword) || toCheck.endsWith("." + keyword) ||
toCheck.startsWith(keyword + ".") || toCheck.contains("." + keyword + ".")){
return true;
}//End if
}//End for
return false;
}//End containsKeyword()
}//End JavaKeywords
So that's all the codes!! My other classes are just GUI classes which has nothing to do with data storing and so i guess i shouldn't post them. Thanks for reading my question and if you have any idea, please help :(
Upvotes: 0
Views: 158
Reputation: 1500165
The problem is that in order to create an LStore
instance, you create an LAddClass
- and in order to create an LAddClass
instance, you create an LStore
instance. So one constructor is effectively calling the other, which is calling the first, etc. The LJKeywords
class is a red herring here, I think - it's just that the LJKeywords
constructor is called when a new LAddClass
instance is created, and that happened to be the straw that broke the camel's back.
Fundamentally, you need to work out how you want the relationship between LStore
and LAddClass
to work. They can't keep constructing each other unconditionally like this.
I'd also strongly advise you to get rid of the L
prefix from all of these class names.
Upvotes: 1
Reputation: 85779
You can find the problem by reading the stacktrace:
LJKeywords
(by at LJKeywords.<init>
(LJKeywords.java:10) message).LAddClass
(by at LAddClass.<init>
(LAddClass.java:8) message).LStore
class (by at LStore.<init>
(LStore.java:9) message).Then, by checking your LAddClass
and LStore
class constructors and fields, I find this:
public class LAddClass{
LJKeywords keyObject = new LJKeywords();
LStore stObject = new LStore(className, methodName,isPrivate);
//...
}
public class LStore {
LAddClass classObject = new LAddClass();
//...
}
So, what's this doing? When you create a LStore
object reference, it will internally create a LAddClass
object reference, which internally will create a new LStore
object reference, which internally will create a LAddClass
object reference, which internally... Ok, now you see where this is going, there's an infinite object instantiation loop here.
What do to to solve this? After removing this infinite loop, you can create LAddClass
and LStore
by separate and associating each other in client class. For example:
class Client {
void foo() {
LAddClass lAddClass = new LAddClass();
LStore lStore = new LStore();
lStore.setLAddClass(lAddClass);
lAddClass.setLStore(lStore);
//...
}
}
Also, I would recommend to change the names of your classes to something more significant. For example, instead of LStore
, use Storage
, and instead of LAddClass
use UMLClass
(or a better suited name).
Upvotes: 1