retry on some exceptions recursive - java

I have a method which uses proxies to retrieve information from a server. Sometimes due to a bad proxy I get SocketException, SSLException, SSLHandshakeException or ConnectException
I want the method to retry on the exceptions above, but on the IOException or no exception I want a string returned
Here is the method I constructed to test different scenarios
public String getTest(int i, int current, int total)
{
String text = "";
try
{
if (i == 1)
throw new IOException();
else if (i == 2)
throw new SSLException("SSLEx");
else if (i == 3)
throw new SocketException();
else
text = "EVERYTHING GOOD";
}
catch (SSLException | SocketException re)
{
if (current < total)
{
System.out.println("Recalling " + current);
getTest(1, ++current, total);
}
}
catch (IOException ioe)
{
text = "HTTP ERROR";
}
catch (Exception e)
{
e.printStackTrace();
}
return text;
}
I call my test method by
System.out.println(c.getTest(3, 0, 5));
Initially the program would catch a SocketException then retry by passing 1 so I can emulate a working proxy but a server response with IOException as i = 1 but the method never returns the text "HTTP ERROR"
What do I need to change in order for this to work as expected?

In order to return the string returned by your recursive function call, you must place return before the recursive function call like so...
return getTest(1, ++current, total);
Right now you are simply running the recursive function and discarding its return value. Your logic then returns your text string from the initial call (which in the case of an SSLException looks like an empty string).
You could also accomplish the same effect by assigning text from the recursive function...
text = getTest(1, ++current, total);
Both statements, considering the rest of your logic, are equivalent.

Related

How to cover IOException from method that has InputStream in JUnit

would like to seek for help on my JUnit testing. On my method, I was able to cover all except the part where IOException needs to be thrown. I have done many workaround on this, but none of it seemed to work.
Here is the method where IOException was not covered on unit test
public String GetstrXMLValue(String strXML, String strCriteria) {
SAXBuilder builder = new SAXBuilder();
builder.setProperty(XMLConstants.ACCESS_S1, "");
builder.setProperty(XMLConstants.ACCESS_S2, "");
Document xmlDocument;
String strValue = "";
ErrorHandler objErrHdl = new ErrorHandler();
try {
InputStream objStream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
xmlDocument = builder.build(objStream);
XPathFactory xpath = XPathFactory.instance();
XPathExpression<Object> expr = xpath.compile(strCriteria);
List<Object> xPathSearchedNodes = expr.evaluate(xmlDocument);
if (xPathSearchedNodes.size() > 0) {
Content content = (Content) xPathSearchedNodes.get(0);
strValue = content.getValue().toString();
}
} catch (JDOMException e) {
objErrHdl.LogError(this.getClass().getName(), "GetstrXMLValue", "ERROR RETRIEVING XML VALUES (XML=" + strXML + ";CRITERIA=" + strCriteria + ")", e.toString());
} catch (IOException e) {
objErrHdl.LogError(this.getClass().getName(), "GetstrXMLValue", "ERROR RETRIEVING XML VALUES (XML=" + strXML + ";CRITERIA=" + strCriteria + ")", e.toString());
} catch (Exception e) {
objErrHdl.LogError(this.getClass().getName(), "GetstrXMLValue", "ERROR RETRIEVING XML VALUES (XML=" + strXML + ";CRITERIA=" + strCriteria + ")", e.toString());
}
return strValue;
}
Here is my JUnit testing
#Test
public void testGetstrXMLValueThrowsIOException() throws IOException, ParserConfigurationException, SAXException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
OutputStream responseBody = new ByteArrayOutputStream();
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
" <RESULT>\r\n" +
" <SHORT_NAME>XXXXXXXXXXXXX</SHORT_NAME>\r\n" +
" <ID_CODE>9999999999999</ID_CODE>\r\n" +
" </RESULT>";
xmlHandler.XMLGenerateRootResult();
xmlHandler.GetstrXMLValue(xml, ".//RESULT/ID_CODE/text()");
try
{
InputStream input = XMLHandlerTest.readXML(xml);
byte[] buffer = new byte[1024];
int bytesRead;
input.close();
while ((bytesRead = input.read(buffer)) > 0)
{
responseBody.write(buffer, 0, bytesRead);
throw new IOException();
}
}
catch(IOException e)
{
System.out.println(e);
}
}
Your question is unclear.
You meant: How do I make the test fail if an IOException occurs
By not catching it. The default behaviour of a test case, if it throws an exception, is that the test case is considered failed. Note that System.out.println(e); is tossing out a humongous amount of useful info about the error, AND means the code will keep going. e.printStackTrace();, LOG.something() or System.out.println() are basically always bugs if you do that in a catch block. Stop doing that. If you can't be bothered to deal with the problem or don't know how, the only correct 'I dunno' code in a catch block is this:
catch (Whatever e) {
throw new RuntimeException("uncaught", e);
}
In this case, just remove the try/catch entirely, and your test will properly fail if an IOException occurs.
You meant: I need to test my method if IT throws an IOException; how do I test that it does the right thing?
Well, there's no point, is there? Your method is obviously broken if an IOException happens, because your method will log something and just keep on going. That's rather silly, and I don't think it's useful for me to try to explain to you how to write a unit test that tests that your method returns the arbitrary misleading value and writes a log message. I don't think anybody would actually want that behaviour.
Make your method throw something on error, and you can easily confirm that it does this with junit. Give it its own test method and annotate:
#Test(expected = IOException.class)
public void testSomething() {
if (Boolean.TRUE) throw new IOException();
// this test will _PASS_, because we said
// it SHOULD throw IOException.
}
You meant: How do I make this method throw IOException?
That's not easily possible unless you kind of ruin your method to make it possible. If you stop catching exceptions and turning them into silly things (a log message and continuing with the code), the code coverage ceases to be an issue. Just get rid of those catch blocks entirely.

Retry after catch

Here's the logic I used:
int retries = config.get("retries");
Response resp = null
do {
try {
resp = operation.execute();
retries = 0;
} catch (Exception ex) { //Note. Please excuse this catch pattern. Its not a problem now.
if isAParticularException(ex) { //call a method to check the wrapped exception and other details
retries--;
LOGGER.info("Integrity exception, can be retried");
if (retries == 0) {
LOGGER.info("Retry exhausted");
throw ex;
}
LOGGER.info("Retrying operation, retry count " + ledgerRetry);
} else {
throw ex;
}
}
} while (retries > 0);
return resp;
Number of retries is considering original operation as well. But the problem is that
if I return from try block directly without assigning anything, then SCA (Fortify for me) reports that the variable retries is not read (in success flow), and
if I assign and do as above, then SCA shouts about the immediate
reassignment of value to the retries variable without even reading
it.
Considerations:
The first call should be independent of whatever value we read for
'retries'
Duplicate code should be avoided, and avoiding recursion will be
nice too.
May be a simple thing, but I am not catching it probably. Please suggest.
Why do you not use break instead of set retries to 0? I guess you sets retries after operation execute, because you want to break executing loop:
int retries = config.get("retries");
Response resp = null
do {
try {
resp = operation.execute();
break;
} catch (Exception ex) {
if isAParticularException(ex) { //call a method to check the wrapped exception and other details
retries--;
LOGGER.info("Integrity exception, can be retried");
if (retries == 0) {
LOGGER.info("Retry exhausted");
throw ex;
}
LOGGER.info("Retrying operation, retry count " + ledgerRetry);
} else {
throw ex;
}
}
} while (retries > 0);
return resp;
Or if you want you can return resp in try catch, and return null if did not execute anything:
int retries = config.get("retries");
Response resp = null
do {
try {
resp = operation.execute();
return resp;
} catch (Exception ex) {
if isAParticularException(ex) { //call a method to check the wrapped exception and other details
retries--;
LOGGER.info("Integrity exception, can be retried");
if (retries == 0) {
LOGGER.info("Retry exhausted");
throw ex;
}
LOGGER.info("Retrying operation, retry count " + ledgerRetry);
} else {
throw ex;
}
}
} while (retries > 0);
return null;
If I were you, I would consider throw exception instead of returning null.

Is is dangerous to have a return statement in the finally clause in java? [duplicate]

This question already has answers here:
Returning from a finally block in Java
(6 answers)
Closed 7 years ago.
Look at the code below. Although the catch clause itself throws an exception, the finally block's return statement causes that exception to be swallowed. This method will return 420 even if something goes wrong in the catch block.
private static int foo() throws Exception
{
try {
throw new Exception("try");
} catch (Exception ex) {
throw new Exception("catch");
} finally {
String s = "";
return 420;
}
}
You should return something else if you encounters an Exception. The exception is only dangerous if the variable that threw that exception is used in the final return statement. Consider this:
int a;
try{
//...
}catch(Exception e){
//a throws an exception somehow
}finally{
returns a;
}
And when you use a on the other side like this:
a += 1;
You get a dangerous exception.
My suggestion is to do this:
try{
//...
}catch(Exception e){
//a throws an exception somehow
returns -1;
}finally{
returns a;
}
And on the other side:
if(return_value == -1) // skip or do something else;
This way, you won't get a unpredicted exception on the other side.
Return in finally is a very bad idea. It doesn't hide only the exceptions you throw yourself, but also virtual machine errors such as stack overflow or out of memory errors. These errors can be thrown at any point, including when the key invariants of data structures don't hold, and it will be impossible to predict what the program will do.
In your case it is safe, but if we change your scenario a little
private static FileReader foo() throws Exception{
try {
throw new Exception("try");
} catch (Exception ex) {
throw new Exception("catch");
} finally {
return new FileReader("");//this may also throw something
}
}
Now, because we didn't specify proper path in your file system return new FileReader(""); will throw FileNotFoundException and we will lose exception thrown in catch section with new Exception("catch"); which is potentially dangerous.

EOFException - how to handle?

I'm a beginner java programmer following the java tutorials.
I am using a simple Java Program from the Java tutorials's Data Streams Page, and at runtime, it keeps on showing EOFException. I was wondering if this was normal, as the reader has to come to the end of the file eventually.
import java.io.*;
public class DataStreams {
static final String dataFile = "F://Java//DataStreams//invoicedata.txt";
static final double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 };
static final int[] units = { 12, 8, 13, 29, 50 };
static final String[] descs = {
"Java T-shirt",
"Java Mug",
"Duke Juggling Dolls",
"Java Pin",
"Java Key Chain"
};
public static void main(String args[]) {
try {
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile)));
for (int i = 0; i < prices.length; i ++) {
out.writeDouble(prices[i]);
out.writeInt(units[i]);
out.writeUTF(descs[i]);
}
out.close();
} catch(IOException e){
e.printStackTrace(); // used to be System.err.println();
}
double price;
int unit;
String desc;
double total = 0.0;
try {
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(dataFile)));
while (true) {
price = in.readDouble();
unit = in.readInt();
desc = in.readUTF();
System.out.format("You ordered %d" + " units of %s at $%.2f%n",
unit, desc, price);
total += unit * price;
}
} catch(IOException e) {
e.printStackTrace();
}
System.out.format("Your total is %f.%n" , total);
}
}
It compiles fine, but the output is:
You ordered 12 units of Java T-shirt at $19.99
You ordered 8 units of Java Mug at $9.99
You ordered 13 units of Duke Juggling Dolls at $15.99
You ordered 29 units of Java Pin at $3.99
You ordered 50 units of Java Key Chain at $4.99
java.io.EOFException
at java.io.DataInputStream.readFully(Unknown Source)
at java.io.DataInputStream.readLong(Unknown Source)
at java.io.DataInputStream.readDouble(Unknown Source)
at DataStreams.main(DataStreams.java:39)
Your total is 892.880000.
From the Java tutorials's Data Streams Page, it says:
Notice that DataStreams detects an end-of-file condition by catching EOFException, instead of testing for an invalid return value. All implementations of DataInput methods use EOFException instead of return values.
So, does this mean that catching EOFException is normal, so just catching it and not handling it is fine, meaning that the end of file is reached?
If it means I should handle it, please advise me on how to do it.
EDIT
From the suggestions, I've fixed it by using in.available() > 0 for the while loop condition.
Or, I could do nothing to handle the exception, because it's fine.
While reading from the file, your are not terminating your loop. So its read all the values and correctly throws EOFException on the next iteration of the read at line below:
price = in.readDouble();
If you read the documentation, it says:
Throws:
EOFException - if this input stream reaches the end before reading eight bytes.
IOException - the stream has been closed and the contained input stream does not support reading after close, or another I/O error occurs.
Put a proper termination condition in your while loop to resolve the issue e.g. below:
while(in.available() > 0) <--- if there are still bytes to read
The best way to handle this would be to terminate your infinite loop with a proper condition.
But since you asked for the exception handling:
Try to use two catches. Your EOFException is expected, so there seems to be no problem when it occures. Any other exception should be handled.
...
} catch (EOFException e) {
// ... this is fine
} catch(IOException e) {
// handle exception which is not expected
e.printStackTrace();
}
You can use while(in.available() != 0) instead of while(true).
Alternatively, you could write out the number of elements first (as a header) using:
out.writeInt(prices.length);
When you read the file, you first read the header (element count):
int elementCount = in.readInt();
for (int i = 0; i < elementCount; i++) {
// read elements
}
You may come across code that reads from an InputStream and uses the snippet
while(in.available()>0) to check for the end of the stream, rather than checking for an
EOFException (end of the file).
The problem with this technique, and the Javadoc does echo this, is that it only tells you the number of blocks that can be read without blocking the next caller. In other words, it can return 0 even if there are more bytes to be read. Therefore, the InputStream available() method should never be used to check for the end of the stream.
You must use while (true) and
catch(EOFException e) {
//This isn't problem
} catch (Other e) {
//This is problem
}
You catch IOException which also catches EOFException, because it is inherited. If you look at the example from the tutorial they underlined that you should catch EOFException - and this is what they do. To solve you problem catch EOFException before IOException:
try
{
//...
}
catch(EOFException e) {
//eof - no error in this case
}
catch(IOException e) {
//something went wrong
e.printStackTrace();
}
Beside that I don't like data flow control using exceptions - it is not the intended use of exceptions and thus (in my opinion) really bad style.
Put your code inside the try catch block:
i.e :
try{
if(in.available()!=0){
// ------
}
}catch(EOFException eof){
//
}catch(Exception e){
//
}
}
EOFException being a child of IOException
I prefer it like below ==>
try {
.
.
.
} catch (IOException e) {
if (!(e instanceof EOFException)) {
throw new RuntimeException(e);
}
}

How do I return a String in a try/catch statment?

I am trying to return a String from the following method.
public String openCon() {
try {
Scanner scan = new Scanner(System.in);
URL sitex = new URL("http://" + scan.nextLine());
URLConnection connection = sitex.openConnection();
Object content = sitex.getContent();
BufferedReader in = new BufferedReader(new InputStreamReader(sitex.openStream()));
String str;
String x = "1";
while ((str = in.readLine()) != null) {
x += str;
}
in.close();
return x;
}
catch(Exception e) {
System.out.println(e);
}
}
The problem isn't returning from the try block - the problem is that you aren't returning anything if an exception is thrown. You're catching the exception... but then reaching the end of the method without returning anything. (To put it in more technical terminology: the end of a non-void method should not be reachable.)
Personally, I would just remove the catch block entirely, and add throws declarations for any exceptions which are thrown within the body. You're not really handling the exceptions - you're just printing them out and ignoring them, which is very rarely a good idea. Catching Exception is usually a pretty bad idea to start with.
As an aside, you should also close your BufferedReader and URLConnection values in a finally block so they're closed even in the case of an exception. I'd also suggest either passing a fixed encoding name to InputStreamReader, or using a higher-level HTTP client API which will use the content-type header from the response. Oh, and use StringBuilder instead of string concatenation in a loop.
Why not initialise the variable before the try statement, and place the return statement after it?
If there's an exception before the return statement, the method won't return anything. Since you're not really handling the exception, I recommend you just let it bubble up and handle it at a higher level. This may be the main method if there's no better place. You will need to declare the method as throws IOException and possibly add other exception classes.
Also, use try-with-resources to ensure your instances (BufferedReader and InputStreamReader) are closed properly.
You should return something in the catch block, for example:
catch(Exception e) {
System.out.println(e);
return "";
}
Use:
String result = ""
try{
result = "OK";
}catch (Exception e){
result = e.toString();
}finally{
return result;
}

Categories