Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does IOUtils.closeQuietly hide the "resource leak" warning?

Background

There is a nice function I use on IOUtils called "closeQuietly" , which closes the stream no matter what is in there.

for example:

InputStream input = null;
try
  {
  ...
  input = connection.getInputStream();
  ...
  } 
catch(Exception e)
  {
  }
finally
  {
  IOUtils.closeQuietly(input);
  }

Somehow, it also hides the warning on Eclipse when I call it in the finally block , of "Resource leak: 'input' is not closed at this location" .

This means that in the above code, there is no such warning.

The problem

I don't understand how it hides the warning on the "outside world" of itself.

What I've tried

I've tried to check it out by copying the code of this library (example here), but the warning appears when I use it on the new class. It doesn't make sense...

here's a sample code i've created to show that the warning will occur on your own classes:

public class MyIOUtils {
    public static void closeQuietly(final InputStream input) {
        if (input == null)
            return;
        try {
            input.close();
        } catch (final IOException ioe) {
        }
    }

    public static void closeQuietly(final OutputStream output) {
        if (output == null)
            return;
        try {
            output.close();
        } catch (final IOException ioe) {
        }
    }
}

usage:

public class Test {
    public void test() {
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream("dummyFile.txt");
            int t = 0;
            --t;
            if (t < 0)
                return; // here you will get a warning
        } catch (final FileNotFoundException e) {
        } finally {
            MyIOUtils.closeQuietly(inputStream);
        }
    }
}

Here's what I see, including the Eclipse version I have being installed:

enter image description here

The question

How does it do it?

like image 897
android developer Avatar asked Oct 20 '22 16:10

android developer


1 Answers

So why does it work for IOUtils? The eclipse team did something very plain - they hardcoded the methods! In previous versions of eclipse the warning was also there however starting from version 4.3 M4 it was gone since they fixed it:

Released for 4.3 M4 via commit 277792ba446c3713bcfdc898c37875d45fc06c18.

The fix covers the following well-known methods:
- com.google.common.io.Closeables.closeQuietly(Closeable)
- com.google.common.io.Closeables.close(Closeable,boolean)
- org.apache.commons.io.IOUtils.closeQuietly(Closeable)

For details see here - especially at the comments at the end...

UPDATE: So what does it mean for you? You have to use one of the obove methods or live with the warning. The check is basically not sophisticated and doesn't check the next level.

Update II: They basically hardcoded the file names. Maybe it is easer to understand with source code. Imagine this is the eclipse code checking for the warning:

public boolean showResourceWarning(){

//do somestuff to detect whether a potential ressource warning is shown
...
    if(resourceLeakWarning){
      if(this.checkForExceptions()){
       return false;
      }
    }
 return resourceLeakWarning;
}

private boolean checkForExceptions(){
    if(name.equals("org.apache.commons.io.IOUtils.closeQuietly(Closeable)"){
     return true;
    }
    if(name.equals("com.google.common.io.Closeables.close(Closeable,boolean)")){
     return true;
    }
    if(name.equals("org.apache.commons.io.IOUtils.closeQuietly(Closeable)")){
     return true;
    }
    // code executed for your method:
    return false;
}

=> The result is, that you don't have a chance to remove the warning other to directly use close() (not in a sub method!) or to use one of the three methods listed above.

Update III: Have a look at the following class TypeConstants.java. Do you see the hardwired names in there? If you want to make it work with your code you need to add your class and method name there and then recompile eclipse. Then look at the class MessageSend.java starting from line 90.

like image 70
Lonzak Avatar answered Oct 23 '22 09:10

Lonzak