akshattandon / projectlombok

Automatically exported from code.google.com/p/projectlombok
0 stars 0 forks source link

Fix @Cleanup #799

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Current "small print" documentation for @Cleanup contains the following remark:

"If your code throws an exception, and the cleanup method call that is then 
triggered also throws an exception, then the original exception is hidden by 
the exception thrown by the cleanup call. You should not rely on this 
'feature'. Preferably, lombok would like to generate code so that, if the main 
body has thrown an exception, any exception thrown by the close call is 
silently swallowed (but if the main body exited in any other way, exceptions by 
the close call will not be swallowed). The authors of lombok do not currently 
know of a feasible way to implement this scheme, but if java updates allow it, 
or we find a way, we'll fix it."

Here's how to fix this problem. Consider the following example:

public static void main(String[] args) throws IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    in.read();
    ...
}

Lombok will expand it as follows:

public static void main(String[] args) throws IOException {
    InputStream in = new FileInputStream(args[0]);
    try {
        in.read();
        ...
    } finally {
        if (in != null) {
            in.close();
        }
    }
}

To obtain the requested behavior, the code above should be expanded instead as 
follows:

public static void main(String[] args) throws IOException {
    InputStream in = new FileInputStream(args[0]);
    try {
        in.read();
        ...
        if (in != null) {
            try {
                in.close();
            } finally {
                in = null;
            }
        }
    } finally {
        if (in != null) {
            try {
                in.close();
            } catch (Throwable e) {
            }
        }
    }
}

This implementation above will work exactly as intended.

Original issue reported on code.google.com by einar.saukas on 19 Mar 2015 at 10:01

GoogleCodeExporter commented 9 years ago
Just a side note. Current implementation of @Cleanup cannot be used outside a 
local variable declaration, like this:

public static void sample(InputStream in, String[] args) throws IOException {
    @Cleanup in = new FileInputStream(args[0]);
    in.read();
    ...
}

However even if @Cleanup was later expanded to support this example above, then 
it would be still possible to implement the requested behavior, as follows:

public static void sample(InputStream in, String[] args) throws IOException {
    in = new FileInputStream(args[0]);
    boolean $pending_in = true;
    try {
        in.read();
        ...
        if (in != null) {
            $pending_in = false;
            in.close();
        }
    } finally {
        if ($pending_in && in != null) {
            try {
                in.close();
            } catch (Throwable e) {
            }
        }
    }
}

Otherwise I still recommend my previous suggestion.

Original comment by einar.saukas on 19 Mar 2015 at 10:09