What is a good practice of dealing with some runtime HTTP exceptions? - java

I have a small method that looks like this:
public static void unstarTrack(Context ctxContext, String strId) {
try {
HttpParams htpParameters = new BasicHttpParams();
List<NameValuePair> lstCredentials = new ArrayList<NameValuePair>();
lstCredentials.add(new BasicNameValuePair("t", String.valueOf(System.currentTimeMillis() / 1000)));
lstCredentials.add(new BasicNameValuePair("__call", "favourites.removeSong"));
HttpPost htpPost = new HttpPost(API_URL);
htpPost.setEntity(new UrlEncodedFormEntity(lstCredentials));
htpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/18.0");
htpPost.addHeader("Accept-Encoding", "gzip");
DefaultHttpClient dhcClient = new DefaultHttpClient(htpParameters);
HttpResponse resResponse = dhcClient.execute(htpPost);
Log.d(TAG, EntityUtils.toString(resResponse.getEntity()));
return;
} catch (SocketException e) {
throw new RuntimeException("problem with network connectivity.", e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Encoding not supported.", e);
} catch (ClientProtocolException e) {
throw new RuntimeException("A protocol exception was encountered.", e);
} catch (ParseException e) {
throw new RuntimeException("An error occurred while trying to read the header elements.", e);
} catch (IOException e) {
throw new RuntimeException("An error occurred while trying to read response stream.", e);
}
}
The method itself is quite simple but it has a bunch of exceptions that an occur and I don't know how I should handle those. Suppressing them by doing a simple ´e.printStackTrace()´ doesn't seem like a nice idea so I began reading up on exception-handling best-practices but I still am a bit lost. What should I do with the exceptions?
I need to do something with my exceptions because I don't want to return null from the method. Returning a null from my method means that the the calling method will have no insight as to whether an exception happened inside my method.
Should I create a custom exception and raise that or should I simply raise unchecked exceptions?
The calling method can't really do much to affect my method i.e. a SocketException may occur if there was a problem with the network connectivity, and a IOException may occur if there was a problem reading the stream. The most that the calling method can do is to retry this at a later time.
If I re-throw all the exceptions that I have trapped, the calling method would simply get riddled with exception-handling blocks.
(I'm sorry if this seems like a trivial question. I'm simply trying to learn to write better code. Thanks.)

Create a dedicated exception, which has the appropriate abstraction level (something like UnstarTrackException). Throw such an exception, wrapping the original exception you caught. That way, the caller will only have to handle one exception (I assume all the exceptions should be handled the same way: retrying).
Whether this exception should be checked or not depends on your taste. If you want to force all the callers of your method to handle this exception, make it a checked exception. If you want to let the caller choose whether he wants to handle this exception or not, use a runtime exception.
If this method is buried deep inside layers of code, and if an exception can only be handled at the top layer, a runtime exception is probably a better choice. And in fact, unless you're the only caller of this method, a runtime exception is also probably a better choice. Checked exceptions tend not to be used much nowadays.

Related

ContextException: Unknown Ban can't be caught (Discord Java)

My unban command sometimes throws a ContextException, when you unban a person who wasn't banned.
I wanted to catch it with a try catch block to notify the user that the person they are trying to unban isn't banned. This is what I tried:
try {
event.getGuild().unban(event.getMessage().getContentRaw().substring(8)).queue();
} catch(ContextException e) {
event.getChannel().sendMessage("This user isn't banned!").queue();
return;
}
But the catch() line just says Exception 'net.dv8tion.jda.api.exceptions.ContextException' is never thrown in the corresponding try block.
Your exception, in this case isn't even a ContextException but an ErrorResponseException. Since queue(...) does asynchronous operations in a different thread, the exceptions cannot be thrown from here. Instead, you should use the failure callback as described by the documentation.
You can use ErrorHandler to handle specific ErrorResponses.
Example:
String userId = event.getMessage().getContentRaw().substring(8);
ErrorHandler handler = new ErrorHandler().handle(ErrorResponse.UNKNOWN_BAN, (error) -> {
event.getChannel().sendMessage("This user isn't banned!").queue();
});
event.getGuild()
.unban(userId)
.queue(null, handler);
The ContextException is only there to tell you where in your code the error originated from. Since the actual exception happens on other threads which give you no context to find the issue.
ContextException handles async exception. So your try block cannot catch the exception.
You can change your code like this.
event.getGuild().unban(event.getMessage().getContentRaw().substring(8)).queue(
null,
(error) -> {
if (error.getMessage().equals("10026: Unknown Ban")) {
event.getChannel().sendMessage("This user isn't banned!").queue();
}
}
);

How to handle all the java.net exceptions in a single catch block?

I am trying to handle the exceptions that are a part of the java.net package. I went through the documentation and I saw 12 exceptions belonging to that package, but I couldn't find the parent class of these exceptions.
So far what I have tried is:
catch(Exception e)
{
if(e instanceof org.openqa.selenium.WebDriverException)
sendException("Problem is with the selenium web driver");
else if(e instanceof java.net.Exception) //I need help with this line
sendException("There is some problem with the network");
}
After trying this, I get the following error message
unable to resolve class java.net.Exception
How can I catch the java.net exceptions?
java.net.Exception doesn't exist and you cannot catch exceptions of classes from a specific package in this way.
Considering that network exceptions always start by java.net is wrong too.
Some network exception don't start by java.net and exceptions can also be wrapped by another exception. For example java.net.SocketException could be wrapped by java.lang.IllegalStateException.
You will not handle it because that is not a java.net exception.
Handling the exception with instanceOf looks not helpful either.
Specifying a specific exception in the catch clause is enough.
Note also that an exception is self-explanatory and should contain in its state all relevant information : you don't need to map the exception to a textual message as you do.
What you want to send/log is exploiting the exception class/message/cause/stracktrace associated to. What you do is just interpretation of the exception meaning that would be error prone.
so do that :
catch(Exception e){
sendException(e);
}
public void sendException(Exception e){
// exploit e.getClass(), e.getMessage() or e.getStackTrace()
...
}
Note that in some cases you want to catch some specific exceptions because you have a specific processing for them :
catch(WebDriverException e){
processWebDriverException(e);
}
catch(Exception e){
processAnyOtherException(e);
}
First off, the reason that you can't catch java.net.Exception. The Exception class is in the java.lang and it is NOT the exception you should be catching.
So what should you catch?
Unfortunately, there there is no suitable supertype for all networking exceptions and no non-networking others. But it turns out that most networking exceptions have java.io.IOException as an ancestor.
(There is one java.net.* exception that doesn't descend from IOException; i.e. java.net.URISyntaxException. But that is an unchecked exception, and it is not indicative of a "network problem".)
So one approach would be to catch IOException. You could further refine this by using reflection to get the package name of the exception class (see https://stackoverflow.com/a/57002571/139985); e.g.
} catch (org.openqa.selenium.WebDriverException e) {
sendException("Problem is with the selenium web driver");
} catch (IOException e) {
if (e.getClass().getPackage().startsWith("java.net"))
sendException("There is some problem with the network");
else {
throw e; // Or diagnose differently
}
}
java.net.Exception doesn't exist, java.lang.Exception does.
To check that the package is java.net, use e.getClass().getPackage():
catch(Exception e)
{
if(e instanceof org.openqa.selenium.WebDriverException)
sendException("Problem is with the selenium web driver");
else if(e.getClass().getPackage().startsWith("java.net"))
sendException("There is some problem with the network");
}
You can catch java.net Exceptions like this :
try {
}
catch (
BindException
| ConnectException
| HttpRetryException
| MalformedURLException
| NoRouteToHostException
| PortUnreachableException
| ProtocolException
| SocketException
| SocketTimeoutException
| UnknownHostException
| UnknownServiceException
| URISyntaxException
e
){
// do stuff with e
}
But what is the point if you are going to call instanceof after to process each exception differently?
In this case you should use different catch blocks.
If there is no common superclass, there is no way to catch these exceptions in a single clause. You might want to check out this post, but I would agree with you that it's not pretty if you have to specify 12 exceptions:
Can I catch multiple Java exceptions in the same catch clause?
Example
Try{
Code where your exception occuring
}
Catch(Exception e){
e.printStackTrace();
}

How do I catch the exception thrown by the code inside a Guava retryer?

I have a Guava retryer around some code:
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfExceptionOfType(Exception.class)
.withStopStrategy(MoreStopStrategies.liveStopAfterAttempt(retries))
.withWaitStrategy(MoreWaitStrategies.liveExponentialWait(TimeUnit.MILLISECONDS, retrySleep, TimeUnit.MILLISECONDS))
.build();
try {
retryer.call(() -> {
return doStuff();
});
} catch (ExecutionException | RetryException e) {
throw Throwables.propagate(e);
}
Let's say doStuff() throws an ArithmeticException. How do I catch that outside the retryer.call()?
So the retryer will try a couple times, fail, and enter into the catch (ExecutionException | RetryException e) block. How would I retrieve the ArithmeticException inside there?
Thanks!
This is a bit of a faulty pattern. You say that any exception is ok to retry. An ArithmeticException will then be ok to retry. This is not what you want.
This is how retries should be implemented. Note the comment on the second line.
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
// .retryIfExceptionOfType(Exception.class)
.withStopStrategy(MoreStopStrategies.liveStopAfterAttempt(retries))
.withWaitStrategy(MoreWaitStrategies.liveExponentialWait(TimeUnit.MILLISECONDS, retrySleep, TimeUnit.MILLISECONDS))
.build();
void doStuff() {
try {
retryer.call(() -> {
doRealStuff();
});
} catch (RetryException e) {
throw new RuntimeException("Call never succeeded", e);
} catch (ExecutionException e) {
Throwables.propagateIfPossible(e.getCause(), ArithmeticException.class);
throw new RuntimeException("Unexpected", e);
}
}
Then when you actually call doStuff:
try {
doStuff();
} catch(ArithmeticException e) {
System.err.println("Arithmetic exception caught:");
e.printStackTrace(System.err);
}
Without seeing your doStuff() or at least knowing what kinds of Exceptions it throws it's hard to answer.
In general, if you have the Retryer consider every Exception unsuccessful, it will retry and eventuelly stop - but it catches any Throwable thrown inside the executed code (see Retryer code, line 162)
The solution is either:
If your doStuff() only throws an ArithmeticException in those cases that result in stopping the Retryer, and that a different kind of Exception marks that a retry is necessary, you can do retryIfExceptoinOfType(OtherException.class). Then, according to the docs the docs
Throws:
java.util.concurrent.ExecutionException - if the given callable throws an exception, and the rejection predicate considers the attempt as successful. The original exception is wrapped into an ExecutionException.
call() will throw an ExecutionException that you can catch outside of the Retryer and inspect the wrapped Exception.
If ArithmeticExcpetion is all doStuff() will throw, and that also indicates that the Retryer should retry, then you can write a custom StopStrategy that throw an ArithmeticExpcetion, it is catched nowhere in the Retryer.
However I advise you to completele rewrite your code, your data flow seems a bit broken. If an ArithmeticExpcetion (or actually even any Exception, as you specify Exception.class in the retryIf ) is to be expected, it should not also be unexpected and need special handling.

Catch Error to Throw Exception

I am working with the ClassLoader class and if there are problems it throws a NoClassDefFoundError. In context this is actually not a fatal error.
Is there a good way to catch the error and throw as exception?
try{
myClassLoader.makeClass(className, classData);
}
catch(Throwable t){
log.error("Class load failed");
// throw as an Exception instead
}
Does this make sense? I don't want this to be fatal but rather just exit without return. The key here is that I want the full stack trace and information associated with the NoClassDefFoundError. It is simple to catch the error it is harder to keep all of the associated information.
throw new Exception("message", t);
t is Throwable
You can catch the exception and throw a new one very easily.
try{
myClassLoader.makeClass(className, classData);
}catch(ClassNotFoundException err){
throw new Exception("Oh no! An error occurred!");
}
Adding onto #bwfcwalshy's answer, we should never catch errors in a Java program. Consider a scenario where program runs out of memory, in this case, an OutOfMemoryError will be thrown. If we have catch block to catch Error (or Throwable), it will catch that error but won't have memory to execute anything, resulting in that error getting suppressed.
We should always catch Exception, not Error or Throwable.
Generally speaking you wouldn't catch a java.lang.Error.
But assuming that this is really what you want to do, you can just catch the Error and throw an Exception.
try {
// Error occurred
} catch(Error e){
throw new Exception("Error", e);
}

Difference between Exception and SQLException

Can someone explain the difference between catching an Exception and catching an SQLException? I know that SQLException will print out more information if you choose to print out the exception errors, but is there anything else?
try {
//code
} catch(Exception ex) {
//code
}
And
try {
//code
} catch(SQLException ex) {
//code
}
What are the benefits and differences of using Exception and SQLException in the catch block?
This is not the only difference.
Catching Exception is dangerous because it also catches all RuntimeExceptions (therefore unchecked exceptions), and that include niceties such as NullPointerException etc which are clear programmer errors. Don't do that!
Also, Exception is a class like any other, so you can subclass it and add constructors/methods of yours. For instance, SQLException has a .getErrorCode() method which Exception does not have. If you only catch Exception, you cannot access this method.
In general, catching the "more precise" exception first is the best. For instance, with the new (in Java 7...) file API, you can easily distinguish between filesystem level errors and other I/O errors, since FileSystemException extends IOException:
try {
something();
} catch (FileSystemException e) {
// fs level error
} catch (IOException e) {
// I/O error
}
It's all about the hierarchy,when you are talking about the catching the exception.
Technically speaking, Exception - is the super class which catches each and every exception.
If you are writing something related to SQL in the try block and you know it may even throw SQL Exception.
Then you may declare it this way as well.
try
{
}catch(SQLException ex)
{
Do this,when SQL Exception is caught.
}
catch(Exception ex)
{
Generic Exception - works for all
}
SQLException inherits from Exception, so SQLException will contain more (and more specific) information than Exception (which is intended to apply generally to all exceptions).
You can also have multiple catch clauses; so you can first try to catch the SQLException, but if it's not a SQLException, then you can just catch the general Exception.
In general, you shouldn't catch exceptions unless you intend to handle them in some way. You can have a top-level exception handler that catches any exceptions that bubble up to the top of the call stack, so that your program doesn't crash on unhandled exceptions.
A - Explanation
SQLException is a subtype of java.lang.Exception and also it is implementing the Iterable<Throwable> class. Programmers prefer throwing different subtypes of Exception class because on some higher level, they want to catch the exact sub-Exception class so that they can be sure that that specific Exception is thrown on some exact scenario. Thus, they can know the exact source of Exception.
B - Example
Consider you have written a method that throws multiple exceptions. Let's say, you take a json String and parse it, then persist it on the database. Consider the following method;
public boolean persistCustomer(String jsonString) throws SQLException, IOException {
Connection conn = getConnection();
PreparedStatement preparedStatement = null;
ObjectMapper objectMapper = new ObjectMapper();
try {
Customer customer = objectMapper.readValue(jsonString, Customer.class);
preparedStatement = conn.prepareStatement(PERSIST_CUSTOMER);
preparedStatement.setString (1, customer.getName());
preparedStatement.setInt (2, customer.getAge());
preparedStatement.setBoolean (3, customer.getIsRegular());
preparedStatement.executeUpdate();
return true;
} catch (IOException e) {
throw e;
} finally {
try {
if (preparedStatement != null)
preparedStatement.close();
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
In this method, we are converting JSON into a Customer class and also we persist customer class to the database.
The following lines throw SQLException;
preparedStatement = conn.prepareStatement(PERSIST_CUSTOMER);
preparedStatement.setString (1, customer.getName());
preparedStatement.setInt (2, customer.getAge());
preparedStatement.setBoolean (3, customer.getIsRegular());
preparedStatement.executeUpdate();
prepareStatement(), setters and executeUpdate() methods, all of them throwing SQLException's. But also, the line that which we convert JSON in a String into a Customer object, also throws several Exceptions other than SQLException.
Customer customer = objectMapper.readValue(jsonString, Customer.class);
readValue() method throws JsonParseException, JsonMappingException and also IOException. All of them can be catched using an IOException because the JSON related exceptions extend IOException.
I'm going to provide two different examples so that it will be obvious to understand why we need different types of Exceptions.
C - Bad Practice: Using Exception To Catch All Exceptions
public class BadPracticeExample {
public static void main(String[] args) {
MySQLUtil dbUtil = new MySQLUtil();
String jsonString = "{\"name\":\"Levent\",\"age\":31,\"isRegular\":true}";
try {
dbUtil.persistCustomer(jsonString);
} catch (Exception e) {
System.out.println("A problem occured");
}
}
}
As you can see, it catches the Exception but what are we going to do if we need special exception handling for two different sources of problems? persistCustomer can throw either IOException or an SQLException and what if we need to do different set of tasks to handle those problems? I want to send an email to the database admin when an SQLException occurs and I want to continue when a JSON parsing problem occurs, on the case that an IOException is catched?
In this scenario you can't do that. Here is the output of the code snippet above and we are only sure that an Exception occured but we don't have any idea about what is the source of it;
A problem occured
D - Good Practice Example I: SQL Exception catched
public class GoodPracticeExample {
public static void main(String[] args) {
MySQLUtil dbUtil = new MySQLUtil();
String jsonString = "{\"name\":\"Levent\",\"age\":31,\"isRegular\":true}";
try {
dbUtil.persistCustomer(jsonString);
} catch (SQLException e) {
System.out.println("SQL Exception catched, SQL State : " + e.getSQLState());
System.out.println("Error Code : " + e.getErrorCode());
System.out.println("Error Message : " + e.getMessage());
} catch (IOException e) {
System.out.println("Cannot parse JSON : " + jsonString);
System.out.println("Error Message : " + e.getMessage());
}
}
}
As you can see, we catch for both, JSON and SQL problem and in this example, submethod is trying to persist DB where there is no table. The output is as below;
SQL Exception catched, SQL State : 42000
Error Code : 1142
Error Message : INSERT command denied to user 'levent'#'example.com' for table 'CUSTOMER'
So we have catched SQL Exception and we have all parameters we need to send an alarm email. We can add additional handler or utility methods on the SQLException catch block.
D - Good Practice Example II: IOExceptoin catched on Parsing Error
public class GoodPracticeExample {
public static void main(String[] args) {
MySQLUtil dbUtil = new MySQLUtil();
String jsonString = "{\"Zname\":\"Levent\",\"age\":31,\"isRegular\":true}";
try {
dbUtil.persistCustomer(jsonString);
} catch (SQLException e) {
System.out.println("SQL Exception catched, SQL State : " + e.getSQLState());
System.out.println("Error Code : " + e.getErrorCode());
System.out.println("Error Message : " + e.getMessage());
} catch (IOException e) {
System.out.println("Cannot parse JSON : " + jsonString);
System.out.println("Error Message : " + e.getMessage());
}
}
}
If you've noticed, I"ve corrupted the JSON to cause an IOException. Now in the json string, instead of "name", "Zname" is written which will cause Jackson Parser to fail. Let's checkout the output of this code.
Cannot parse JSON : {"Zname":"Levent","age":31,"isRegular":true}
Error Message : Unrecognized field "Zname" (class com.divilioglu.db.utils$Customer), not marked as ignorable (3 known properties: "isRegular", "name", "age"])
at [Source: (String)"{"Zname":"Levent","age":31,"isRegular":true}"; line: 1, column: 11] (through reference chain: com.divilioglu.db.utils.MySQLUtil$Customer["Zname"])
As you can see, we catched the specific scenario and we are sure, this comes from the line in dbUtil.persistCustomer() method which can be seen below;
Customer customer = objectMapper.readValue(jsonString, Customer.class);
E - Conclusion
So as it is a best practice to create new Exceptions by extending existing Exception classes. While writing your code at first, you may think that it is an overkill and you won't need additional Exception classes, but you will need them when you need distinguish the source of the problem and handle them independently.
In this example demonstrated above, I can independently catch IOException and SQLException and the sources of both Exceptions are coming from the same method. I want to distinguish both so that I can handle them independently. You cannot have that flexibility if you just wrap all the Exceptions with the base Exception class.
Exception is a standard class from which every exceptions inherit.
SQLException is a class that inherits from Exception and that is designed specifically for database(SQL) exceptions.
By doing
try {
// Your code here
} catch (Exception e) {
// Catching here
}
You are catching every type of exception possible... But then, you might not be able to know how to react to a specific exception.
but by doing
try {
// Your code here
} catch (SQLException e) {
// Catching here
}
You know that the exception happened while working on a database and it helps you know how to react to the exception.
As you see SQLException extends exception. So that's the only difference really. When you are catching exception then you will catch ALL exceptions (which is bad). But when you are catching SQLException then you catch only that(which is good because that is what you are seeking).
If an exception in between the try and catch blocks is thrown that is not a SQL Exception (these will typically only come from database-related code), for example a Null Pointer Exception, the Exception catch will catch it but the SQLException will not.
SQLException is an Exception so you are just getting a more specific exception.
According to Oracle's javadocs, this specific information you get is:
a string describing the error. This is used as the Java Exception
message, available via the method getMessage.
a "SQLstate" string, which follows either the XOPEN SQLstate
conventions or the SQL:2003 conventions. The values of the SQLState
string are described in the appropriate spec. The DatabaseMetaData
method getSQLStateType can be used to discover whether the driver
returns the XOPEN type or the SQL:2003 type.
an integer error code that is specific to each vendor. Normally this
will be the actual error code returned by the underlying database.
a chain to a next Exception. This can be used to provide additional
error information.
the causal relationship, if any for this SQLException.
SQLException is a specialized exception derived from Exception.
If you catch Exception, all exception shall get caught. Even undesirable exceptions.
If you catch only its specialiazation, the SQLException, only the SQLException itself or its derived shall get caught.
One shall catch only exceptions one can handle or wishes to handle, and let the others bubble up.
For further reference, please take a look at the following:
Exception
SQLException
SQL exception is a frequent error while working in Java Database Connectivity (JDBC).Its related to accessing or setting column in your SQL Query using prepared statement.
SQLException is a derived from Exception and contains more specific information related to accessing or setting column in your SQL query, while exception is usually more general.

Categories