I'm trying to traverse a list of objects and print out their properties to an xml file, but due to the need of closure tags I need to recursively traverse the children and print their properties as well before coming back to the top of the stack to write out the highest components closure tag.
It seems however that for-loops and recursion do not play well together in java, as for some bizarre reason when I have a method call itself inside of the for loop, the counter "resets" (essentially the counter variable seems to unassign itself when trying to use the for-loop normally with all 3 arguments) when coming to the next iteration of the loop, causing an infinite loop.
I've tried a number of different approaches, including trying to make the counter a static variable in the classes constructor and substituting in a for-each loop instead, all with similar problems. The closest I've come to finding an answer was the following solution, with passing in and returning the counter into the recursive method:
Adding counter to a loop inside a recursive method - Java
However, while this works for the case above, which consists of just adding to a value, it causes problems in that if I don't adjust the counter, it is now one higher than it needs to be and causes indexOutOfBound exceptions, and if I do subtract the counter and/or assign it to 0 before entering the loop, the return is giving back a 0 even if I explicitly add one to the counter before passing it back.
None of this makes any sense. Here is the basic logic of the code I'm using: if anyone knows what is wrong with this, or knows of any alternative solutions, let me know.
public int write(PrintWriter fromPortalTXTFile, String level, Integer counter){
...
if (children) {
for(;counter < childrenList.size();) {
counter++;
counter = ClassName.get(counter - 1).write(fromPortalTXTFile, level, counter);
}
}
else {
counter++;
}
return counter;
}
EDIT: Here is the entire method code due to various requests. It contains references to different functions and has logic unrelated to the problem I'm having, and I can't go into detail about how every part of this method works. The problem is with the for loop that is entered if the component has children, which I still believe is better illustrated above.
// Writes the information about this BOM component out to the from_portal.txt file
public int write(PrintWriter fromPortalTXTFile, String level, Integer counter) throws Exception {
//Retrieve the item and revision of the BOM line. If
//read access is denied, skip the BOM line.
Debug.println("PERF: Inside printXMLTag: Reading BOMLine props start");
TCComponentItem item = TXDExportAction.getItem(currentComponent);
TCComponentItemRevision rev = TXDExportAction.getItemRevision(currentComponent);
//if (item == null || rev == null) {
// return null;
//}
String itemID = item.getProperty("item_id");
String revID = rev.getProperty("item_revision_id");
// Get the pdm_occ_id of the current component
String pdmOccID = TXDExportAction.getBOMLineProperty(currentComponent, "bl_occurrence_uid");
// Determine if the item is currently selected in the BOM window
Boolean isSelected = false;
//if (selectedComponents.contains(currentComponent)){
// isSelected = true;
//}
// TODO: See if it is actually needed to get the quantity of packed lines
//If the user created a single occurrence to represent
//multiple occurrences, get the quantity
int n = 1;
boolean packed = currentComponent.isPacked();
if (!packed) {
try {
//String str = icbl.getProperty("bl_quantity");
String str = TXDExportAction.getBOMLineProperty(currentComponent, "bl_quantity");
if (str != null) {
n = Integer.parseInt(str);
}
} catch (NumberFormatException e) {
//Do nothing
}
}
Debug.println("PERF: Inside printXMLTag: Reading BOMLine props complete");
//TODO: See why this is in a loop, and if it is necessary
XMLStringBuffer buf = new XMLStringBuffer();
//Loop over the BOM line n times
for (int count = 0; count < n ; count++) {
//Build the opening XML entry
//XMLStringBuffer buf = new XMLStringBuffer();
buf.startTag(TXDExportAction.BOMLINE);
buf.appendAttribute(TXDExportAction.ITEM_ID, itemID);
buf.appendAttribute(TXDExportAction.REV_ID, revID);
buf.appendAttribute(TXDExportAction.PDM_OCC_ID, pdmOccID);
buf.appendAttribute(TXDExportAction.ITEM_SELECTED, isSelected);
// If this is not the lowest level tag, don't put in the slash at the end.
// If it is, close the tag.
//TODO: Remove writing of tags, add to the BOMElement.write function.
//if (closureTags == 0){
// buf.endTagBracket();
//}
//else{
// buf.endTag();
// //Handle closure tags for parents
// for(int i = 0; i < closureTags; i++){
// buf.endTag(BOMLINE);
// }
//}
}
buf.endTagBracket();
// Step 3: write a </bomline> tag at the same level
fromPortalTXTFile.print(level);
fromPortalTXTFile.println(buf);
//buf.endTag(TXDExportAction.BOMLINE);
if (!childBOMElements.isEmpty()){
// Step 1: print tag + information
level = level + " ";
// Step 2: for each child, call child.write()
for (; counter < childBOMElements.size();){
counter ++;
//BOMElement nextElement = childBOMElements.get(index);
counter = childBOMElements.get(counter - 1).write(fromPortalTXTFile, level, counter);
}
// </Bomline> tag
//fromPortalTXTFile.println(buf.endTag(TXDExportAction.BOMLINE));
}
else
{
// If no children, close the tag with a leaflet
//fromPortalTXTFile.println(buf);
counter++;
fromPortalTXTFile.print(buf.endTag());
}
// For some reason, using a recursive function in a for loop resets the counter of the for loop.
// The only work-around is to pass the counter back as a return method.
return counter;
}
childrenList[counter-1]isn't an integer. Something seems to be wrong with the logic.