Home > front end >  Java Compiler adding additional else part and moving last return statement in that else part
Java Compiler adding additional else part and moving last return statement in that else part

Time:10-08

I am working in java tech stack for a quite while but have not seen such type issue. I have a method which has a return statement at the end and an if statement in between without else part. When I compile my class, compiler generates a class where this method has additional else block at the end and last statement (which is my return statement is moved into else part added by compiler). I need to understand why compiler is doing such thing and what's wrong with the code which makes it to such thing.

Java Method

public String convertFromHtmlToDBTextTemplates(final String html, final String convertTo, XPathMapping xPathMapping) {

    //Editor specific code to replace Colour classes to Codes classes for DB
    String result = colourCodesClassConversion(html, convertTo);

    result = result.replaceAll(HTML_START_POINT_UPPER, HTML_START_POINT);
    result = result.replaceAll(HTML_SPAN_UPPER_END, HTML_END_POINT);
    //Replacing UI Label with the corresponding XPath reading mapping from the passed XPathMapping
    if (IMCollectionUtils.isNotEmpty(xPathMapping.getXPathElements().getXPathElement())) {
        for (XPathMapping.XPathElements.XPathElement xpathElement : xPathMapping.getXPathElements().getXPathElement()) {
            result = result.replaceAll(LESS_THAN_CHARACTER   xpathElement.getUILabel()   GREATER_THAN_CHARACTER,
                    XPATH_WRAPPER_ELEMENT   xpathElement.getXPath()   CLOSING_BRACKET);
            if (xpathElement.getChildElements() != null && IMCollectionUtils.isNotEmpty(xpathElement.getChildElements().getChildElement())) {
                for (XPathMapping.XPathElements.XPathElement.ChildElements.ChildElement childElement : xpathElement.getChildElements().getChildElement()) {
                    if (result.contains(LESS_THAN_CHARACTER
                              xpathElement.getUILabel()
                              UI_LABEL_SEPARATOR
                              childElement.getUILabel()
                              GREATER_THAN_CHARACTER)) {
                        result = result.replaceAll(
                                LESS_THAN_CHARACTER
                                          xpathElement.getUILabel()
                                          UI_LABEL_SEPARATOR
                                          childElement.getUILabel()
                                          GREATER_THAN_CHARACTER,
                                XPATH_REPEATING_WRAPPER_ELEMENT
                                          xpathElement.getXPath()
                                          REPEATING_ENTITY_SEPARATOR
                                          childElement.getXPath()
                                          CLOSING_BRACKET);
                    }
                }
            }
            
        }
    }
    return result;
}

Compiled code is

public String convertFromHtmlToDBTextTemplates(String html, String convertTo, XPathMapping xPathMapping) {
    String result = this.colourCodesClassConversion(html, convertTo);
    result = result.replaceAll("<SPAN", "<span");
    result = result.replaceAll("</SPAN>", "</span>");
    if (IMCollectionUtils.isNotEmpty(xPathMapping.getXPathElements().getXPathElement())) {
        Iterator var5 = xPathMapping.getXPathElements().getXPathElement().iterator();

        while(true) {
            XPathElement xpathElement;
            do {
                do {
                    if (!var5.hasNext()) {
                        return result;
                    }

                    xpathElement = (XPathElement)var5.next();
                    result = result.replaceAll("&lt;"   xpathElement.getUILabel()   "&gt;", "XPATH:{"   xpathElement.getXPath()   "}");
                } while(xpathElement.getChildElements() == null);
            } while(!IMCollectionUtils.isNotEmpty(xpathElement.getChildElements().getChildElement()));

            Iterator var7 = xpathElement.getChildElements().getChildElement().iterator();

            while(var7.hasNext()) {
                ChildElement childElement = (ChildElement)var7.next();
                if (result.contains("&lt;"   xpathElement.getUILabel()   ":"   childElement.getUILabel()   "&gt;")) {
                    result = result.replaceAll("&lt;"   xpathElement.getUILabel()   ":"   childElement.getUILabel()   "&gt;", "XPATHRE:{"   xpathElement.getXPath()   "#"   childElement.getXPath()   "}");
                }
            }
        }
    } else {
        return result;
    }
}

'''

CodePudding user response:

There is nothing wrong with the decompiled code. It looks confusing, but the return statement is inside the inner do-while loop and not at the end of if block itself.

if (...) {
  Iterator var5 = ...
  while (true) {
    XPathElement xpathElement;
    do {
      do {
        if (!var5.hasNext()) {
          return result; // return if iterator has no more elements
                         // this return statement is always reached
        }
        result = ... // perform first replacement
      } while (...); // if there are no child elements continue iteration, otherwise jump to outer do-while loop
    } while (...); // if collection is empty continue iteration (this is the && part of your second if statement)

    while () { // iterate child element
    }
    // we are still inside while(true) loop
    // jump back to 'XPathElement xpathElement;' line
  }
} else {
  return result; // this return statement is not needed to complete the if(true) case
}

CodePudding user response:

I need to understand why compiler is doing such thing

The compiler isn't the thing that's introducing the difference: it's the decompiler.

In general, there are an infinite number of Java source code inputs that can produce the same bytecode output. The obvious example of this is that renaming a variable leaves the bytecode unchanged; but other examples exist, such as if (condition) return; else statement; and if (condition) return; statement;.

As such, the decompiler almost certainly cannot produce the exact source code you put into the compiler. It can only recognise patterns in the bytecode, and say "this bytecode is most often produced by people writing code like this..."; or, "this bytecode is most simply produced by people writing code like this". That may be how you wrote it; it may not be.

In the case of this code:

if (condition) {
  while (true) {
    if (condition2) {
      return result;
    }
  }
}
return result;

Because the while loop can never complete normally (it returns, or keeps looping: the condition is constant, and there is no break inside the loop), it never reaches the final return; so that return is effectively in an else.

if (condition) {
  while (true) {
    if (condition2) {
      return result;
    }
  }
} else {
  return result;
}

So, the decompiler produces this code because it is equivalent.

  • Related