【发布时间】:2018-08-21 19:13:45
【问题描述】:
您好,提前感谢您。我在这里相对较新,到目前为止,我已经能够解决我在搜索中遇到的任何问题,但这个问题让我很难过。
我正在编写一个程序,该程序使用 Rest-Assured 进行 API 调用以获取云服务器中不同对象的配置文件。这些对象是我们可以称之为文件夹的组织文件容器。这些文件夹具有特定的结构,每个文件夹都有特定的元数据配置文件。我的程序所做的是从返回的 JSON 创建 java 对象,并以允许它们仍然像文件夹结构一样工作的方式存储它们,以便可以操作它们来执行以下操作:打印文件夹结构,获取特定的子文件夹文件夹、查看特定文件夹的名称或 ID、添加或删除文件夹等。
我已将其设置为每个文件夹都是一个对象,其中包含其子文件夹的 ArrayList 和元数据变量,其中构造函数将根据 JSON 填充所有变量。
在使用我的递归方法调用 API 并将子文件夹添加到它们应该去的位置之后,在类内部的方法中,我可以看到它们已正确添加,一旦方法退出,如果我尝试访问来自 Main 的列表我得到一个空指针异常。请参阅下面的代码示例。
编辑:我在下面的代码中添加了额外的测试,以检查递归方法中的数组索引是否为空。创建对象时,构造函数使用indexOf() 打印 ArrayList 中的文件夹 ID 和索引。当它从构造函数返回时,在相同的递归方法中,getSingleFolder(index).getSubfolders().get(0).getSubfolders().get(0).toString 仍然为 null,即使这应该返回刚刚从构造函数中创建并添加到父文件夹 ArrayList(并已验证)的同一文件夹。
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));
}
}
根据要求,getFolderProfileFromRestApi() 和 getFoldersJsonArrayFromRestApi() 方法只需使用 Rest-Assured 进行调用并返回一个 GSON JsonObject,其中包含构造函数所需的信息或它们的功能所需的方法,我已经使用过这些有点,并已验证它们按预期工作。调用folder.addSubfolder() 调用文件夹构造函数并返回新文件夹,以便它可以用于获取它自己的文件夹等。我已经非常广泛地使用了它并验证它确实返回了正确的信息并且构造函数被调用.如果我将 System.out 检查放在实际的 folder.addSubfolder() 方法中,我可以访问数组中的元素,因为它们仍然存在,但当控制返回到 main 时似乎消失了。
Folder 类中的 addSubfolder 方法如下所示。我添加了系统输出来检查并确保一切都在发生,实际上这些都添加到了它们应该添加的位置。这里的输出完全符合预期。
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;
}
当我返回 Main 时,我编写了一个小型递归方法,仅使用名称以标准格式打印结构,并且它似乎可以工作,直到它到达一个有 3 级的地方,然后它当它尝试访问该级别的第一个元素时抛出空指针异常。
相反,我使用特定代码为刚刚创建并在 addSubfolder 方法中检查的确切嵌套子文件夹调用 toString,它还返回空指针异常。即
server.getSinglefolder(1).getSubFolders().get(0).getSubFolders().get(0).toString();
据我所知,这是另一个 StackOverflow 帖子
Objects disappearing of ArrayList
有同样的问题,但我似乎无法理解如何根据我的情况转换解决方案,或者它是否不起作用,因为我不应该这样做。感谢您的帮助!
编辑:我再次查看了该帖子,似乎他的问题是他后来的代码正在更改它,但他没有注意到,因为它是一个参考。我不认为这是这种情况,因为在该方法返回后,该对象不会再次被访问,直到它在 main 中调用并返回为空。我现在整天都在搜索和阅读文章,这一定是我看不到的愚蠢的东西。再次感谢您的帮助。
编辑 2:经过进一步测试,我注意到添加到 ArrayList 的文件夹可以在构造函数中使用this 获取对象并调用获取器的 ID 来验证。但是,当从调用构造函数的递归方法的末尾访问时,ArrayList 在该索引处为空(添加到代码示例的 System.out 测试)。因此,实际上,只要构造函数返回,arraylist 在控制甚至返回到 main 之前再次为 Null。这可能与我在方法中声明占位符对象(文件夹、子文件夹、newSubfolder)并因此在退出时被清除的事实有关吗?即使是这种情况,即使临时引用消失,对象本身仍应保存更改。
编辑 3:根据要求,这里是 folder.hasSubFolders() 和文件夹构造函数的方法。
private boolean hasSubfolders;
public boolean hasSubfolders() {
return hasSubfolders;
}
从 addSubfolder 中调用的文件夹构造函数。请注意,整个构造函数大约 150 行,但格式相同,检查 JSON 中的成员,如果存在,将值保存到类变量。如果有人真的认为有必要,我可以发布整个内容。
//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();
}
...}
编辑 5:程序每个部分的 ideone 链接。它当然不会在没有访问其余服务器的情况下运行,但不幸的是我无法共享连接信息。我可以向您保证,其余调用正常运行并准确返回其应有的数据,并且所有这些数据都得到正确处理(以一种可行的方式正确处理,但可能不是最佳实践)-_-
注意:我知道我需要清理抽象类及其实现方式,我还有很多工作要做来清理编码实践,但这远未完成,只有一半-完成了我正在测试的程序。但是,由于我一直在学习,因此我完全愿意接受该领域的任何建议。谢谢
主要 - https://ideone.com/Y2FYrm
IMContainer - https://ideone.com/TFdiqk
文件夹 - https://ideone.com/gX4nda
【问题讨论】:
-
详细问题值得点赞
-
这条语句“server.getSinglefolder(1).getSubFolders().get(0).getSubFolders().get(0).toString();”是一条长链。你能知道它在哪个点表示法上引发了空指针异常吗?
-
谢谢@Mr.Brickowski!我同意它有点长而且令人费解,但在这种情况下,我只能检查那里是否有元素。我在它上面添加了相同的字符串( legendDev.getSingleTemplate(1).getSubFolders().get(0).toString(); 并取消了一个级别,因为在递归方法进入之前添加了第一级并且它确实打印和不会在那里抛出异常。我怀疑我的递归有问题。奇怪的是,如果从递归方法中执行,上面的字符串仍然有效,它只有在方法退出时才为 null。
-
有些领域是未知的。你能提供 Folder() 构造函数和 Folder.hasSubfolders() 实现吗?另外,整个系统可以同时运行吗?即线程安全类型的东西。
-
@Mr.Brickowski 感谢您一直以来的关注和帮助!我真的在这里绞尽脑汁。正如我可能已经提到的那样,我对编写超出课堂和教科书练习的功能的 Java 程序还比较陌生,所以我不确定我是否熟悉线程安全,但我会做我的研究。非常感谢您可以指出我的任何资源。至于并发运行,整个程序由 Main/psvm 控制,只需几行即可运行服务器方法进行连接、添加子文件夹然后尝试打印它们。