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("<" xpathElement.getUILabel() ">", "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("<" xpathElement.getUILabel() ":" childElement.getUILabel() ">")) {
result = result.replaceAll("<" xpathElement.getUILabel() ":" childElement.getUILabel() ">", "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.