The following java code runs in an IntentService; it works; it uploads an image to twitter.
I have coded it with a separate try-catch at each call that throws an IOException.
I have removed code at the ... spots to make it quicker to read.
try {
con = (HttpURLConnection) new URL(Constants.TWITTER_ENDPOINT_UPLOAD_MEDIA).openConnection();
} catch (IOException e) {
e.printStackTrace();
}
...
con.setDoOutput(true);
try {
os = con.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
DataOutputStream out = new DataOutputStream(os);
try {
write(out, boundary + "\r\n");
...
} catch (IOException e) {
e.printStackTrace();
}
try {
statusCode = con.getResponseCode();
} catch (IOException e) {
e.printStackTrace();
}
My question is:
Does it make sense to put one or more of these calls inside a re-try loop, like this:
for (int i = 0; ; i++) {
try {
httpURLConnection = (HttpURLConnection) new URL(Constants.TWITTER_ENDPOINT_UPLOAD_MEDIA).openConnection();
break;
}
catch (IOException e) {
if (i < 3) {
continue;
}
else {
reportErrorToCallingActivity();
return;
}
}
}
And, if it does make sense, at which ones?
And, if for example I were to need to re-try at:
statusCode = con.getResponseCode();
how much code should I re-run: all the way back to openConnection?
I just can't figure this out from the documentation,
and I don't want to just guess at what to do. Hope you can help!
I appreciate this is probably greatly cut-down, but I think the giveaway here is that when you catch your IOExceptions all you do is log them to the console. In other words, your code doesn't know what to do, what state it (or the connection) is in, or how to proceed. Given that checking exception message text is bad practice, the exception type just doesn't give good enough information. In that case, the simplest and most honest thing is to rethrow the original exception in the hope that the calling code knows more / can handle the error better.
If, at any stage, you (or your code) are confident you can fully/largely deal with an exception, then have an explicit try/catch the way your current code does. But if you don't, your method should 'fess up' and declare that it throws IOException without trying to handle them at all. (Make sure you have a finally block to clean up any resources you've created in the process!)
Provided your method is honest and cleans up after itself, the calling method can potentially retry in a loop - as per your second code example. However, without any controls on retrying (number of attempts, backoff, etc.) and without any good guidance from the connection API, it's probably unwise to keep trying, potentially wasting resources, getting rate-limited, breaching T&Cs etc.
A better solution would be to obtain a Twitter access library that returns meaningful status messages, and that can potentially handle its own retries.
Edit:
By far the most useful line is statusCode = con.getResponseCode(); which gives you a value you can check against Twitter's Error Codes list. In general, if you get 2xx back, your request has succeeded, 4xx means your code has done something wrong, 5xx means Twitter has done something wrong. At least that lets you adjust your error message if you - as you probably should - bail out rather than try to work around it.
It looks like 420 and 429 best indicate that you can retry. However, you will need to do so much more carefully than just repeating your request in an endless loop. You should definitely read the Rate Limits doc for guidance.
Related
The problem I'm trying to solve is like this: I'm trying to scrape some content from a web page, I'm using selenium, findElementByClassName to get the element content, and it works great until now. But considering that the website that I'm scraping changes one of those element classes in html, I don't want to get an could not find element exception making the rest of the code not execute and jumping straight into the catch block.
My idea was to put each line of code into a try catch block, but having about 15 fields that I want to scrape it makes the code look ugly. See for yourself:
String name = null;
String type = null;
String description = null;
try {
driver.get(link);
try {
name = driver.findElementByClassName(environment.getProperty("booking.propertyName")).getText();
}catch (Exception e){
log.error("error doing thing");
}
try {
type = driver.findElementByClassName(environment.getProperty("booking.propertyType")).getText();
}catch (Exception e){
log.error("error doing thing");
}
try {
description = driver.findElementByClassName(environment.getProperty("booking.propertyDescription")).getText();
}catch (Exception e){
log.error("error doing thing");
}
}catch (Exception e){
log.error("Error during scraping");
}
So if one of these things goes wrong, I still want the rest of the code to continue instead of when having one try-catch block where the first thing failing would stop the other things from executing.
The code above works just fine but it does not look good so my question do you have any ideas of how I could make this better looking.
There is no magic bullet for this. But the standard way avoid repetitive code is to refactor. For example:
try {
type = driver.findElementByClassName(environment.getProperty("something"))
.getText();
} catch (Exception e){
log.error("error doing thing");
}
can be rewritten as:
type = getElementTextIgnoringExceptions(driver, environment, "something");
where getElementTextIgnoringExceptions has been defined as something like this:
public String getElementTextIgnoringExceptions(
Driver driver, Environment env, String name) {
try {
String className = env.getProperty(name);
return driver.findElementByClassName(className).getText();
} catch (Exception ex) {
log.error("error getting " + name, ex);
return null;
}
}
However ... there are some bad things about the code that you are trying to simplify here:
Catching Exception is bad. You have no idea what you will catch, or whether it is safe or sensible to continue.
Not logging the exception is bad. How are you going to diagnose the problem if all you have an "error doing thing" message in your log file?
Continuing after the exceptions is (in the context of your application) liable to cause problems. The rest of your code will be littered with null checks to deal with the elements (or whatever) that couldn't be fetched. Miss one check and you are liable to get an NPE; e.g. in some edge-case that you didn't cover in your unit tests.
These issues are more significant than making the code look good.
If you are using Java 8+, it may be possible to refactor so that the logic is passed as lambda expressions. It depends on the nature of the variables used.
I am trying to get HTTP codes from websites.
When I parse sites without threads, one-by-one, everything is fine.
But if I use threads, sometimes I receive
java.sql.SQLException: After end of result set
at
URL url = new URL(rset.getString("url"));
I think that the problem is in timeouts, and tried to break the cycle if timeout is > then I want.
if (connection.getConnectTimeout()>10)
{
System.out.println("timeout");
break;
}
But it seems that it never works. What am I doing wrong? Thank you. The full part of problem code is below.
static class JThread extends Thread {
JThread(String name){
super(name);
}
public void run() {
try {
while (rset.next()) {
System.out.println("hello");
URL url = new URL(rset.getString("url"));
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
if (connection.getConnectTimeout()>10)
{
System.out.println("timeout");
break;
}
//Thread.sleep(1000);
int code = connection.getResponseCode();
System.out.println(code);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Thread stopped");
}
}
I am trying to get HTTP codes from websites. When I parse sites without threads, one-by-one, everything is fine. But if I use threads, sometimes I receive
java.sql.SQLException: After end of result set
at
URL url = new URL(rset.getString("url"));
This has nothing to do with HTTP timeouts. The exception you are getting is because you are trying to get the "url" column from a database row after you have already read all the results (and there are no more results to read).
You say this only happens when you use multiple threads. It looks like a thread enters the while loop (rset.next() is true). Then another thread calls rset.next() (moving past the end of the result set), gets false, and doesn't enter the loop. Then the first thread tries to get the URL, but you've already gone past the last result.
You should synchronize access to the ResultSet (or any object) if it is shared between multiple threads, but it would probably be better to just not share the ResultSet between threads. A better way to split the work would be to have a single thread get the URLs from the database, and 1 or more threads do the HTTP connection (e.g. thread pool, new thread per URL, etc.).
You need to synchronize the calls to ResultSet.next() and check beforehand if it has been exhausted.
Now you have two threads calling it the same time and the first one gets the last row and the next one tries to get a row when the result set is already exhausted.
I have a question about Java method introspection, specifically concerning exceptions. Say I have the following code:
private String getCustomReportResponse(HttpsURLConnection customReportConnection) {
int responseCode = 0;
try {
responseCode = customReportConnection.getResponseCode();
return httpResponseBodyExtractor.extractResponseBodyFrom(customReportConnection);
} catch (IOException e) {
translateIntoRelevantException(responseCode, e);
}
}
Let's say both statements in the try block are capable of throwing an IOException - in which case, the translateIntoRelevantException method is invoked, which looks like this:
private void translateIntoRelevantException(int responseCode, IOException e) {
if(is5xxResponseCode(responseCode)) {
throw new ServerResponseException("Could not generate report - returned response code " + responseCode, e);
}
throw new ReportException("GeminiReportException: Unable to parse response from HTTP body when requesting custom Gemini report.", e);
}
So, whatever happens, either a String is returned, or an exception is thrown. Except the getCustomReportResponse method does not compile without adding a return statement after the catch block, which is absolutely unreachable. In fact, if I put the contents of translateIntoRelevantException inside the catch block, it compiles, which seems daft to me.
I should add, the exceptions being thrown are runtime exceptions, but I've also tried making them checked exceptions, but the problem persisted.
Could someone please explain why?
This is a common problem that "rethrow" helper methods face.
The compiler does not know (and there is no way to indicate) that the method translateIntoRelevantException will never return.
As such, it thinks that there is a code-path that continues after try block. So you have to put in a "dead-code" return null (or throw new RuntimeException("should never come here").
You don't have to put it after the try block, you can put it inside the catch.
try {
responseCode = customReportConnection.getResponseCode();
return httpResponseBodyExtractor.extractResponseBodyFrom(customReportConnection);
} catch (IOException e) {
translateIntoRelevantException(responseCode, e);
throw new RuntimeException("should never come here");
}
It's probably prettier to have the helper just return the exception instead of throwing it. Then you can do
throw translateIntoRelevantException(responseCode, e);
Compilation of getCustomReportResponse should not rely on the implementation of translateIntoRelevantException for multiple reasons:
implementation of translateIntoRelevantException might not be available (it could be in a separate class, in a separate library);
otherwise any change in translateIntoRelevantException could break all of the calling methods.
As an alternative you can return an exception and then throw it in a client code:
private IOException translateIntoRelevantException(int responseCode, IOException e) {
if(is5xxResponseCode(responseCode)) {
return new ServerResponseException("Could not generate report - returned response code " + responseCode, e);
}
return new ReportException("GeminiReportException: Unable to parse response from HTTP body when requesting custom Gemini report.", e);
}
then call it like this:
throw translateIntoRelevantException(responseCode, e);
I load a xml content, and save it to the disk. Then I read it, and try to parse.
When I have successfully parsed xml, should I ignore IOException in 7 line?
catch (IOException ignore) {}
Or some problems may occured?
private HashMap <String, VideoDto> loadContent(String url){
try {
BufferedInputStream bStream = httpGateway.loadContents();
cachedContent = xmlParser.parseVideos(bStream);
try {
bStream.close();
} catch (IOException ignore) {}
return cachedContent;
} catch (XMLStreamException e) {
throw new IllegalStateException("I/O error during integration", e);
}
}
public BufferedInputStream loadContents() {
URL source = config.getContentPath();
URL target= config.getLastImportedFile();
try {
ReadableByteChannel rbc = Channels.newChannel(source.openStream());
FileOutputStream fos = new FileOutputStream(target.getFile());
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Wrong url format", e);
} catch (IOException e) {
throw new IllegalArgumentException("I/O error while saving "+target, e);
}
return createBufferStream(config.getLastImportedFile());
}
private BufferedInputStream createBufferStream(URL url){
try {
return new BufferedInputStream(url.openConnection().getInputStream());
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
There are three parts to this question:
Q1: Should one ever ignore (squash) an exception?
I think that the answer is ... "it depends".
If the exception cause is known AND it you can catch it precisely (i.e. without also catching exceptions with different causes) AND the correct thing to do is to ignore it then ... IMO ... Yes it is acceptable.
Otherwise. No.
Q2: What does and IOException mean in this case, and does it matter?
The answer is that it is not at all clear. Under normal circumstances, one would not expect an IOException when closing an input stream, and it is hard to know what it might mean. Intuitively it is probably harmless. On the other hand, if you don't know what might cause something it is hard to say whether or not it matters.
Q3: Should you simply ignore this IOException?
I would say no. But I would handle it like this:
} catch (IOException ex) {
// possibly log the exception here.
throw new AssertionError("Unexpected exception", ex);
}
The rationale is that if something totally unexpected does occur, then it would be a good thing if the developer / maintainer could find out, and figure out how to deal with it.
On the other hand, if you could make an a priori assessment that any IOException here is harmless, then simply logging (or even squashing) it might be sufficient.
Never ignore exceptions, even if nothing goes wrong. This is the seed of bugs.
The desired thing to do, if you don't need any actions to be done, is, print its stack trace.
e.printStackTrace();
You may ignore that at any time, but may help you in the long run.
Use the try syntax that exists since Java 7:
try (BufferedInputStream bStream = httpGateway.loadContents();) {
cachedContent = xmlParser.parseVideos(bStream);
}
With this you don't have to call .close() manually.
You should catch all exceptions that are thrown inside the try block, though.
This means that the stream will (probably) still be open, whether that is a problem in your program only you will know. At the very least you should log the exception, otherwise you might get strange results that are hard to detect.
You might also want to look at the try-with-resources syntax which doesn't pose this dilemma:
try (BufferedInputStream bStream = httpGateway.loadContents()) {
cachedContent = xmlParser.parseVideos(bStream);
}
In Effective Java Joshua Bloch gives this as an example of an exception you might want to log and ignore. He says, however, that in general you want to do more than just logging an exception.
I've been looking all over for an answer to this and have yet to find one.
Basically I am trying to connect to a database server through a GUI. My boss wants to be able to enter all fields and then check to see if they are valid entries, then if there are any invalid entries, he wants me to turn the text red, indicating that the field is invalid. I have the try statement catch ClassNotFoundException and SQLException. Because there are multiple fields that need to be checked, I have tried to have a set of if statements to check the connection info. Here is the code below, I hope this makes sense...
//The cancel boolean values in this code are used elsewhere to regulate the Threads
try
{
//attempt connection here
}
catch(ClassNotFoundException | SQLException e)
{
String[] errors = new String[4]; //This will create a String array of the errors it catches
//and will later get called into a method that displays
//the messages in a JOptionPane.showMessageDialog()
if (e.getMessage().startsWith("The TCP/IP connection to the host"))
{
errors[0] = "SQL CONNECTION FAILED: Please check the server URL you entered to make sure it is correct.";
cancel = true;
mGUI.serverNameTextField.setForeground(Color.RED);
}
if (e.getMessage().startsWith("Login failed for user"))
{
errors[1] = "LOGIN FAILED: You do not have sufficient access to the server.";
cancel = true;
}
if (e.getMessage().startsWith("Cannot open database"))
{
errors[2] = "SQL CONNECTION FAILED: Please check the database name you entered to make sure it is correct.";
cancel = true;
mGUI.dbNameTextField.setForeground(Color.RED);
}
mGUI.reportErrors(errors); //Method where it reports the String[] array of errors
//However, the 'errors' parameter only returns one error
//message at a time, which is the problem.
Thanks for any help!
****EDIT******
I found a solution, so hopefully this will help someone. I changed my if statements to add an AND argument checking for the specific error code. You find find the error code by either setting a break point and looking at the debug perspective, or you can do what I did and set a print statement to see the error code. Here is the print statement:
System.out.println(((SQLException) e).getErrorCode());
Here are my new for statements:
try
{
//attempt connection here
}
catch(SQLException | ClassNotFoundException e)
{
if (e instanceof SQLServerException && ((SQLServerException) e).getErrorCode() == 0)
{
//code here
}
else{
//code here
}
System.out.println(((SQLException) e).getErrorCode()); //Here is the print statement to see the error code.
if (e instanceof SQLServerException && ((SQLServerException) e).getErrorCode() == 4060)
{
//code here
}else{
//code here
}
if(cancel != true)
{
//code here
}
}
You can do it in multiple ways
1 having more than one catch with a common function
}catch (ClassNotFoundException e){
handleError(e);
}catch (SQLException e){
handleError(e);
}
where handleError takes the exception as the argument.
You dont seem to do anything else so you can just combine them both into a single exception
}catch(Exception e){
}
which will catch everything but you have MUCH less control over the error handling.
A general principle of exceptions is that they are handled at the point they are best abled to be handled.
You seem to have very disparate exceptions and presumably a TCP exception thrown somewhere in the code is not the same as the SQLException thrown when connecting to a database (I might be wrong here since I don't know what the rest of the code looks like). So would not a set of exception handlers, one for each type make more sense. Also to reite from Bryan Roach, text disambiguation is not a good idea.
try {
...
} catch (java.net.SocketException e) {
e[0] = "tcp error";
} catch (java.sql.SQLException e) {
e[1] = "sql exception happened";
}
Also your string array seems a bit risk, possibly a
ArrayList errors = new ArrayList();
errors.add("Some tcp error");
errors.add("Some db error");
and then for you error reporting
mGUI.reportErrors(errors.toArray())
would preserve your interface and not waste you having to allocate extra elements to the array and have empty entries. I don't know exactly what your question is, but you allude to the GUI not displaying multiple errors. Possibly there is a check which stops at the first empty element in an array. Say e[2] and e[4] is populated, it might stop when it iterates over the errors as e[3] is empty. I'm presuming again since I don't know what that code looks like
From the comments above it sounds like what you want to do is have different logic for the various Exception types you are catching within a single catch block. If this is the case, you could go:
...
catch(ClassNotFoundException | SQLException e) {
String[] errors = new String[4];
if (e instanceof ClassNotFoundException) {
//do something here
}
if (e instanceof SQLException) {
//do something else here
}
...etc
}
This should work, but it's probably just as easy to use multiple catch blocks as others have suggested:
}catch (ClassNotFoundException e){
handleError(e);
}catch (SQLException e){
handleError(e);
}
I don't mean any offense, but the way the code handles exceptions might cause some headaches down the road. For example:
if (e.getMessage().startsWith("Cannot open database")) {
Here the code relies on the supporting library that throws the exception to use the same text description, but this description might change if you switch to another JVM version, use a different database driver, etc. It might be safer to go by the exception type, rather than the exception description.