Potnetial Resource Leak with IOUtils Persists like a Stubborn Mule - java

I'm using IOUtils to parse JSON from a HttpServletRequest request:
baseRequest.setAuthentication(null);
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
baseRequest.setHandled(true);
PrintWriter writerResponse = response.getWriter();
-> String data = IOUtils.toString(request.getInputStream(), "UTF-8"); <-
But Eclipse complains of a potential resource leak:
Potential resource leak: '<unassigned Closeable value>' may not be closed
Even when I surround it with a try/finally block and close via IOUtils.closeQuietly() the error persists like a stubborn mule.
String data = "";
try {
data = IOUtils.toString(request.getInputStream(), "UTF-8");
} catch (IOException e) {
} finally {
IOUtils.closeQuietly(request.getInputStream());
}
What is causing this error and how do I fix it?
P.S
While the code below:
try {
String data = IOUtils.toString(request.getInputStream(), "UTF-8");
} catch (IOException e) {
} finally {
IOUtils.closeQuietly(request.getInputStream());
}
does not throw any error, as soon as I try using the value 'data' anywhere in my code (even in the try statement) the error shows up again.

The error is correct. getInputStream may well return a new input stream each time you call getInputStream, so closing a new input stream doesn't help.
Save the input stream in a variable. Best of all, use try-with-resources:
try (InputStream stream = request.getInputStream()) {
data = IOUtils.toString(stream, "UTF-8");
}

Related

Resources closed but sonarlint still showing resource not closed

I have defined Output stream like below
OutputStream os=new FileOutputStream(file);
Tried to close the resource like below
if(os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}}
Still sonarlint showing "Use try-with-resources or close this "FileOutputStream" in a "finally" clause."
If you are doing the operations in the same method it's important to put the close in a finally statement of a try that envolves the open part of the stream. This ensures that in case of failure (Exception) the stream is allways closed if required
Bad sonar code:
OutputStream os=new FileOutputStream(file);
... // your code operations with os
// If something is going really bad here and ends in exception the
// stream will never be closed
if(os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Better code:
OutputStream os = null;
try{
os = new FileOutputStream(file);
... // your code operations with os
} finally{
// The stream is allways closed at the end of the method execution
if(os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
The best code (in case of Java 1.7 or upper)
try (OutputStream os = new FileOutputStream(file)){
... // your code operations with os
// The stream is allways closed at the end of the try block
}
Try this instead. You do not do a close when using try with resources, that is automatically handled... i.e.
"The try-with-resources statement ensures that each resource is closed
at the end of the statement."
try( OutputStream os=new FileOutputStream(file) ) {
....
}
Any resources declared within the brackets are closed automatically once the program flow has completed whether an exception is thrown or not..
Examples here : https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

Will this InputStream be closed properly if an IOException occurs?

I'm trying to properly handle an IOException without having to resort to a tonne of nested try/catch statements.
From reading online I've gathered that this might be the correct way to handle it. but I'm not 100% sure. Is this right?
try (InputStream in = blob.getBinaryStream()) {
while (in.read(bytesRead) != -1) {
byteStream.write(bytesRead);
}
}catch(IOException e){
logger.error("An IOException occurred while streaming a blob from the database", e);
}
The InputStream in will be closed, byteStream not.

Catching Same IOException Inside Catch IOException Block

My Android code is behaving funny. The input stream should and does throw an IOException, which correctly causes control to go to // read an error stream. The error stream is read correctly and the debugger steps to return error_message with the error_message variable containing expected characters read from error stream. It then correctly steps to the // no op in the finally block, which I added just for kicks.
And then, it steps to return "all hope lost";!! Which then, instead of returning to the caller, steps into some Android system code that throws a SecurityException with a message about lack of content permissions.
Removing the finally block has no impact -- the bug still happens. The streams being read are from an HTTP URL Connection. No problems if server returns 200 but if server returns 400 it goes through the weird path described above and tries to throw the weird SecurityException.
try {
// read an input stream into message
return message;
} catch (IOException outer) {
try {
// read an error stream into error_message
return error_message;
} catch (IOException inner) {
return "all hope lost";
}
} finally {
// no op, just to step debugger
}
Update: Posting exact code and debug trace.
try {
/*x*/ BufferedReader buffered_reader =
new BufferedReader(
new InputStreamReader(
new BufferedInputStream(http_url_connection.getInputStream())));
StringBuilder string_builder = new StringBuilder();
String line;
for (line = buffered_reader.readLine();
line != null;
line = buffered_reader.readLine()) {
string_builder.append(line);
}
return string_builder.toString();
} catch (IOException io_exception) {
this.io_exception = io_exception;
BufferedReader buffered_reader =
new BufferedReader(
new InputStreamReader(
new BufferedInputStream(http_url_connection.getErrorStream())));
StringBuilder string_builder = new StringBuilder();
try {
for (String line = buffered_reader.readLine();
line != null;
line = buffered_reader.readLine()) {
string_builder.append(line);
}
/*y*/ String error_message = "server error: " + string_builder.toString();
return error_message;
} catch (IOException exception) {
String level_2_error_message = "level 2 error: " + exception.getMessage();
return level_2_error_message;
} finally {
return "foo";
}
}
Line /*x*/ causes the jump to the first catch as expected. All lines up to /*y*/ are then executed as expected. Then the weird thing is that line /*y*/ does not complete and control immediately goes to either the next catch block if there is no finally or to the finally. If there is a finally then it does not to got the last catch block.
The contents of the string buffer on /*y*/ line look perfectly fine -- a 20 character string from the server.
You say that an exception is being thrown by line /* y */
By my reading of that line of code, the following are plausible explanations:
The exception is a NullPointerException because string_builder is null. But it can't be.
The exception is an OutOfMemoryError because you don't have enough free space for the toString() call to create the new String object.
It is possible that StringBuilder is not java.lang.StringBuilder but some class you wrote yourself. In that case, any exception is possible.
However, I can't see how you would end up in the second IOException handler.
Apart from that, the only other likely explanation is that that source code does not match the code that you are actually executing; e.g. you forgot to recompile something, or you forgot to redeploy after your last compilation.
For what it is worth, your return in your finally is almost certainly a mistake.
It means that you will return "foo" instead of either of the error messages.
If (for example) string_builder.toString() did throw an NPE or OOME, then the return would squash it.
A finally with a return can have non-intuitive behaviour. It is certainly NOT something you should do "for debugging"!!!

File locked after uploaded by using HttpServletRequest in JAVA

Here is the scenario, I try to upload a file, and after I uploaded it, I tried to access that file from the new directory (which i just write to), but I received error message:
There was an error opening this document. The file is already open or
in use by another application.
Below is my coding.
try{
conn = this.getConnection();
String getIP = "SELECT IP FROM TABLE WHERE ID='3'";
ps = conn.prepareStatement(getIP);
rs = ps.executeQuery();
Part file = request.getPart("upload");
String fileName = extractFileName(request.getPart("upload"));
String basePath = "//"+ipAdd+"/ns/"+fileName;
File outputFilePath = new File(basePath + fileName);
inputStream = file.getInputStream();
outputStream = new FileOutputStream(outputFilePath);
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
}catch(Exception ex){
ex.printStackTrace();
throw ex;
}finally{
if(!conn.isClosed())conn.close();
if(!ps.isClosed())ps.close();
if(!rs.isClosed())rs.close();
inputStream.close();
outputStream.close();
}
Is it because that I open the file too quick after I start the upload function? I do realize that after 1/2minutes, I'm able to access the file. Is there anyway to solve this bug?
You're not closing the file. Add
outputStream.close();
after the loop.
EDIT And do it first, before closing anything else. You should really use try-with-resources here. If you get any exception closing anything, the other closes won't happen.
In your code above, if an exception occurs whilst closing the JDBC Connection, then none of the other JDBC objects or Streams are closed. The finally block exits at that point.
Since Java 7, closing Streams and JDBC objects (Connections, Statements, ResultSets etc) can be done in a proper exception handling framework nice and easily, since they all implement a common interface AutoCloseable
So you can write a single close() method and handle the exception inside:
public void close(AutoCloseable closeable) {
try {
closeable.close();
} catch (Exception e) {
//Just log the exception. there's not much else you can do, and it probably doesn't
//matter. Don't re-throw!
}
}
So when closing your JDBC objects, you can do this in the finally block:
close(conn);
close(ps);
close(rs);
close(inputStream);
close(outputStream);
Now if an exception occurs whilst closing any of the objects, it is handled and the following objects are still closed.

Resource leak: 'in' is never closed, though it IS closed

I know that there are a couple of similarly entitled questions out there, but most of them have simply forgotten to put a close() directive on their stream. This here is different.
Lets say I have the following minimal example:
public void test() throws IOException
{
InputStream in;
if( file.exists() )
{
in = new FileInputStream( file );
}
else
{
in = new URL( "some url" ).openStream();
}
in.close();
}
This give me a Resource leak: 'in' is never closed warning in Eclipse (Juno SR1).
But when I move the in.close() into the conditional block, the warnings vanishes:
public void test() throws IOException
{
InputStream in;
if( file.exists() )
{
in = new GZIPInputStream( new FileInputStream( file ) );
in.close();
}
else
{
in = new URL( "some URL" ).openStream();
}
}
What is going on here?
Because of the IO exception, you can run into a resource leak (poentially)
Try doing the following:
public void test() throws IOException
{
InputStream in= null;
try {
if( file.exists() )
{
// In this case, if the FileInputStream call does not
// throw a FileNotFoundException (descendant of IOException)
// it will create the input stream which you are wrapping
// in a GZIPInputStream (no IO exception on construction)
in = new GZIPInputStream( new FileInputStream( file ) );
}
else
{
// Here however, if you are able to create the URL
// object, "some url" is a valid URL, when you call
// openStream() you have the potential of creating
// the input stream. new URL(String spec) will throw
// a MalformedURLException which is also a descendant of
// IOException.
in = new URL( "some url" ).openStream();
}
// Do work on the 'in' here
} finally {
if( null != in ) {
try
{
in.close();
} catch(IOException ex) {
// log or fail if you like
}
}
}
}
Doing the above will make sure you've closed the stream or at least made a best effort to do so.
In your original code, you had the InputStream declared but never initialized. That is bad form to begin with. Initialize that to null as I illustrated above. My feeling, and I'm not running Juno at the moment, is that it sees that the InputStream 'in', may potentially make it through all the hoops and hurdles to get to the point at which you are going to use it. Unfortunate, as someone pointed out, your code is a bit dodgy for an example. Doing this as I've detailed as well as #duffymo you'll get rid of the warning.
Here's how I'd write it:
public void test() throws IOException
{
InputStream in = null;
try {
if(file.exists()) {
in = new FileInputStream( file );
} else {
in = new URL( "some url" ).openStream();
}
// Do something useful with the stream.
} finally {
close(in);
}
}
public static void close(InputStream is) {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
I suspect the warning is incorrect. It could be checking you are closing the stream in the same scope. In the second case, you are not closing the second stream.
Your in stream may not be initialized if the file doesn't exist and you try to close a non-existent file.
Your second example would also need a close statement to avoid leaks.
This same Eclipse reporting can happen when you explicitly throw an exception after you have opened your resource like:
public void method() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("myfile.txt"));
while (br.ready()) {
String line = br.readLine():
if (line.length() > 255) {
throw new IOException("I am some random IOException");
}
}
br.close();
}
This is some contrived code for demonstration purposes so don't look too hard.
If one were to comment out the line, the warning goes away. Of course, you instead want to make sure that that resource is being closed properly. You could do:
if (line.length() > 255) {
br.close();
throw new IOException("I am some random IOException");
}
Do not rely on the Eclipse warnings in this case though. Get in the habit of using the try/finally approach to make sure that resources are correctly and consistently being closed.
I have something like:
InputStream content = httpResponse.getEntity()==null?null:httpResponse.getEntity().getContent();
that gives the same warrning. But if I leave it just like this:
InputStream content =httpResponse.getEntity().getContent();
I receive no warrnings. Isn't strange or what?
-- I hope my info is adding knowledge to the original question. Thanks!

Categories

Resources