New ArrayList Objects Disappear When Method Exits

New ArrayList Objects Disappear When Method Exits



Hello and thanks in advance. I'm relatively new here and thus far I've been able to solve any issues I've come across from searching but this one has me stumped.



I'm writing a program that uses Rest-Assured to make API calls to get the Profiles of different objects in a cloud server. These objects are organizational file containers that we can call folders. The folders have a specific structure with a specific profile of metadata for each one. What my program does is creates java objects from the JSON that is returned and stores them in a way that allows them to still work like a folder structure so they can be manipulated to do things like: print the folder structure, get subfolders of a specific folder, view name or ID of a specific folder, add or remove a folder, etc.



I've set this up so that each folder is an object that contains an ArrayList of its subfolders and variables for the metadata where the constructor will fill all of the variables based on the JSON.



After using my recursive method to call the API and add the subfolders where they're supposed to go, within the method inside the class I can see that they were added correctly, once the method exits, if I try to access the list from Main I get a Null Pointer Exception. See code samples below.



EDIT: I have added additional tests to the code below to check if the array index is null from within the recursive method. When the object is created, the constructor prints the folder ID and the index in the ArrayList using indexOf(). When it returns from the constructor, in the same recursive method, getSingleFolder(index).getSubfolders().get(0).getSubfolders().get(0).toString is still null even though this should be returning the same folder that was just created and added to the parent folders ArrayList (and verified) from within the constructor.


indexOf()


getSingleFolder(index).getSubfolders().get(0).getSubfolders().get(0).toString


public void saveSubfoldersRecursively(Folder folder){
if (folder.hasSubfolders())
getFolderSubfoldersJsonArrayFromRestApi(folder);

for(int x = 0; x < folder.getFoldersJsonArray().size(); x++)
JsonObject currentSubfolderJson = folder.getFoldersJsonArray().get(x).getAsJsonObject();
JsonObject fullSubfolderProfileObject = getFolderProfileFromRestApi(currentSubfolderJson);
Folder newSubfolder = folder.addSubfolder(fullSubfolderProfileObject);

if (newSubfolder.hasSubfolders())
saveSubfoldersRecursively(newSubfolder);


if (folder.getId().equals("<folderID>") )
System.out.println("inside saveSubfoldersRecursively"); // this prints fine
// Null Pointer Exception at next line!
System.out.println("access test 1: " + folder.getId() + " subfolder at index 0: " + folder.getSubFolders().get(0));




As requested, the getFolderProfileFromRestApi() and getFoldersJsonArrayFromRestApi() methods simply make a call with Rest-Assured and return a GSON JsonObject containing the information needed in the constructor or method that is needed for their function, I've used these quite a bit and have verified them to be working as intended. Calling folder.addSubfolder() calls the folder constructor and returns the new folder so that it can then be used to get it's own folders, etc. I've used this pretty extensively and have verified that it does return the proper info and the constructor is called. If I put System.out checks within the actual folder.addSubfolder() method, I can access the elements in the array as they are still there but seem to disappear when control goes back to main.


getFolderProfileFromRestApi()


getFoldersJsonArrayFromRestApi()


folder.addSubfolder()


folder.addSubfolder()



The addSubfolder method within the Folder class looks as below. I added the System outs to check and be sure that everything was happening and these are in fact added where they're supposed to. The outputs here are exactly as expected.


public Folder addSubfolder(JsonObject folderProfile)
System.out.println("Adding " + folderProfile.get("id") + " to subfolders of " + this.getId()); //this is a check to be sure the folderProfile passed has the right folderID and has been passed ot the right parent folder. this also returns the correct info in all cases
Folder subfolder = new Folder(folderProfile);
this.subFolders.add(subfolder);
System.out.println("subfolder added at index " + this.subFolders.indexOf(subfolder)); //This is just a check to see that the subfolder is now in the array and it does return the correct index.
return subfolder;



When I return to Main, I've written a small recursive method to print the structure in a standard format using the names only and it seems to work until it gets to a place where there would be a 3rd level, then it throws a null pointer exception when it tries to access that first element of that level.



Conversely, I used specific code to just call the toString for the exact nested subfolder that was just created and checked in the addSubfolder method, and it also returns a null pointer exception. i.e.


server.getSinglefolder(1).getSubFolders().get(0).getSubFolders().get(0).toString();



As best I can tell, this other StackOverflow post



Objects disappearing of ArrayList



had the same problem, but I can't seem to understand how to convert the solution for my situation or if it's not working because I shouldn't be doing it this way. Thanks for your help!



Edit: I've reviewed that post again and it seems his issue is an issue with the fact that his later code was changing it but he didn't notice because it was a reference. I don't think this is the case here since after that method returns, the object isn't accessed again until it's called in main and comes back empty. I've been searching and reading articles ALL DAY now and this has got to be something stupid that I just can't see. Thanks again for your help.



Edit 2: After further testing, I've noticed that the folder that is added to the ArrayList is verifiable within the constructor using this to get the object and call the getter for it's ID. However, the ArrayList is then null at that index when accessed from the end of the recursive method that calls the constructor (System.out tests added to code sample). Thus the arraylist is Null again before control even returns to main, as soon as the constructor returns, actually. Could this be something to do with the fact that I declare my placeholder objects (folder, subfolder, newSubfolder) from within the method and thus they are cleared when it exits? Even if that was the case the object itself should still hold the changes even if the temporary reference is gone.


this



Edit 3: as requested, here are the methods for folder.hasSubFolders() and folder constructor.


folder.hasSubFolders()


private boolean hasSubfolders;


public boolean hasSubfolders()
return hasSubfolders;



Folder Constructor that is called from within addSubfolder. please note the whole constructor is about 150 lines but it follows the same format, check for member in JSON, if it exists, save value to class variable. I can post the whole thing if anyone really thinks it's necessary.


//main constructor, parses response string to JSON and pulls all data to fill class variables.
public Folder(JsonObject folderProfile)

if (folderProfile.has("database"))
this.database = folderProfile.get("database").getAsString();


if (folderProfile.has("default_security"))
this.defaultSecurity = folderProfile.get("default_security").getAsString();

...



Edit 5: ideone links for each of the parts of the program. It wont run without access to the rest server of course but unfortunately I can't share the connection info. I can assure you that the rest calls function properly and return exactly the data their supposed to, and that all of that data is handled correctly (correctly as in a way that works, but maybe not best practice) -_-



Note: I am aware that I need to clean up the abstract class and the way it is implemented, I have a LOT of work left to do for cleaning up the coding practices but this is far from complete and only a half-finished piece of program that I'm testing. However I am completely open to any suggestions in that realm as I'm always learning. Thanks



Main - https://ideone.com/Y2FYrm



IMContainer - https://ideone.com/TFdiqk



Folder - https://ideone.com/gX4nda



Template - https://ideone.com/7VfkPX



Server - https://ideone.com/geJazD





detailed question deserves a upvote
– Mr. Brickowski
Aug 22 at 2:57





This statement "server.getSinglefolder(1).getSubFolders().get(0).getSubFolders().get(0).toString();" is a long chain. Can you tell at which dot notation it throws the null pointer exception?
– Mr. Brickowski
Aug 22 at 3:06





Thank you @Mr.Brickowski! I agree it's a bit long and convoluted but in this case it's only so I can check if there is an element there. I added the same string above it ( legendaryDev.getSingleTemplate(1).getSubFolders().get(0).toString(); and took off one level since the first level is added before the recursive method comes in and it does print and does not throw an exception there. I suspect there's something wrong with my recursion. The odd part continues that the above string works if executed from within the recursive method, it's only null when the method exits.
– John Ciociola
Aug 22 at 3:54





Tthere are some areas of unknown. Can you provide Folder() constructor and Folder.hasSubfolders() implementation? Also, could the whole system running in concurrent manner? i.e. Thread safety kind off stuff.
– Mr. Brickowski
Aug 23 at 1:53






@Mr.Brickowski thanks for your continued interest and help! I've really been racking my brain here. As I may have mentioned, I'm relatively new to writing Java programs that are functional beyond classroom and textbook exercises so I'm not sure that I'm familiar with thread safety but I will do my research. Any resources you can point me to are much appreciated. As for running concurrently, the whole program is controlled by Main/psvm which is just a few lines long to run the server methods to connect, add subfolders and then attempt to print them.
– John Ciociola
Aug 23 at 2:12





2 Answers
2



I suspect when you are recursively adding a folder to your folder arrayList, you are not adding the subfolders to the added subfolders. This creates a scenario where the subfolders the third recursion throws a NullPointerException. If this is the only problem, moving


if (newSubfolder.hasSubfolders())
saveSubfoldersRecursively(newSubfolder);



to the beginning of the method might help.



However, without knowing the implementation of


getFolderSubfoldersJsonArrayFromRestApi



or


getFolderProfileFromRestApi



I can't say for sure.





Thanks so much for your help, the REST API first returns an array with elements that represent the folder profiles, but due to limitations in this API these elements are missing key metadata. what I do is save the full array to the object as a seperate JsonArray, then use that list to call the API to get the full profile for each folder. getFolderProfileFromRestApi is just a Rest-Assured call that returns a JsonObject that contains the full profile that is needed for the constructor. In this case, I have to first create the newFolder Object from the REST response.
– John Ciociola
Aug 22 at 3:59





It is also worth noting that inside the class, within the addSubfolders method, the checks show the correct index when using .indexOf(subfolder) right after its been added, but return null when accessed later within main. As far as I can tell I have added the subfolders correctly since they are there at one point during the execution.
– John Ciociola
Aug 22 at 4:14



I agree Chi-Young Jeffrey Lii's answer, and this is a further elaboration on that.
addSubfolder() basically did 3 things.


addSubfolder()


public Folder addSubfolder(JsonObject folderProfile)
System.out.println("Adding " + folderProfile.get("id") + " to subfolders of " + this.getId());
// 1.create new subfolder
Folder subfolder = new Folder(folderProfile);
// 2.add subfolder to this subFolders arraylist
this.subFolders.add(subfolder);
System.out.println("subfolder added at index " + this.subFolders.indexOf(subfolder));
// 3.return subfolder
return subfolder;





Illustrated below
enter image description here



When the statement executed (match the highlight color with diagram color), the blue part is an empty ArrayList, if you call .get(0), it will return a null. If you call toString() on a null variable, it will throw null pointer exception.
enter image description hereenter image description here


ArrayList


.get(0)


toString()



Since we do not have access to all the code, so this is the best assumption we can guess for the root cause.



I think you are confused why getting the index within addSubfolder() works but when you check it in saveSubfoldersRecursively(), it gives you error. It is because two statement points to different reference.


addSubfolder()


saveSubfoldersRecursively()


System.out.println("access test 1: " + folder.getId() + " subfolder at index 0: " + folder.getSubFolders().get(0));



is not equal to


System.out.println("subfolder added at index " + this.subFolders.indexOf(subfolder));



I bet if you write this at the last line of addSubfolder() will give you exception as well.


addSubfolder()


System.out.println("subfolder's subfolder null check:" + subfolder.getSubFolders().get(0).toString());



Explanation on the source code given. I found Folder has its own subFolders and Template has its own too. They are different List of Folder, how you add a subfolder to Folder class can be retrieved back from Template?



enter image description here





I really appreciate the time you took to draw out this diagram. I've looked over the code and I believe I wasn't clear when I posted the sample. the orange folder in your example is actually the root level folder of a template. in my program, templates and folders both implement the abstract class of container. so in reality when I run the program there would be one more layer, causing all the colors to bump down one notch and lining everything up to the point where it works. This is why it's so confusing to me because I can access this array and index from within addsubfolder() but not after
– John Ciociola
Aug 23 at 3:14





I can definitely post the whole program or at least share it by some other means since it may be unwieldy to post here. Is there a preferred method for doing so? It seems lazy to just post 1000 lines into an edit or something.
– John Ciociola
Aug 23 at 3:31





could ideone.com fit?
– Mr. Brickowski
Aug 23 at 3:34





thanks I will add the links to the bottom of the current question!
– John Ciociola
Aug 23 at 3:56





I have added the links to the Main question, Thanks for the suggestion and thanks again for your help.
– John Ciociola
Aug 23 at 4:11






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)