Search code examples
javaautocloseable

Wrapping multiple AutoCloseables


try-with-resources is nice and all that, but it seems to me that it is still not sufficient for effective resource management when creating classes that wrap multiple AutoCloseable objects. For example, consider

import java.io.*;

class AutocloseableWrapper implements AutoCloseable {
    private FileReader r1;
    private FileReader r2;

    public AutocloseableWrapper(String path1, String path2) throws IOException {
        r1 = new FileReader(path1);
        r2 = new FileReader(path2);
    }

    @Override
    public void close() throws IOException {
        r1.close();
        r2.close();
    }

    public static void main(String[] args) throws IOException {
        try (AutocloseableWrapper w = new AutocloseableWrapper("good-path", "bad-path")) {
                System.out.format("doing something\n");
                throw new IOException("doing something in main");
            }
    }
}

There are at least two issues with this wrapper:

  1. If "bad-path" is invalid and causes the assignment to r2 to throw, then r1 is not closed.
  2. If wrapper construction succeeds but then r1.close throws, then r2 is not closed.

All those issues can be addressed, but then writing the wrapper becomes quite non-trivial and error-prone, even if wrapping only two resources:

import java.io.*;

class AutocloseableWrapper implements AutoCloseable {
    private FileReader r1;
    private FileReader r2;

    public AutocloseableWrapper(String path1, String path2) throws IOException {
        r1 = new FileReader(path1);
        try {
            r2 = new FileReader(path2);
        }
        catch (IOException e) {
            try {
                r1.close();
            }
            catch (IOException e2) {
                e.addSuppressed(e2);
            }
            throw e;
        }
    }

    @Override
    public void close() throws IOException {
        IOException e = null;
        try {
            r1.close();
        }
        catch (IOException e1) {
            e = e1;
        }

        try {
            r2.close();
        }
        catch (IOException e2) {
            if (e == null)
                throw e2;
            else {
                e.addSuppressed(e2);
                throw e;
            }
        }
    }

    public static void main(String[] args) throws IOException {
        try (AutocloseableWrapper w = new AutocloseableWrapper("good-path", "bad-path")) {
                System.out.format("doing something\n");
                throw new IOException("doing something in main");
            }
    }
}

Is there some helper class or any other way to make writing wrappers easier?


Solution

  • You should enable the syntactic code unwrapped by the compiler....You can find the Oracle article over here :- http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html

    Coming to the question,if you have a wrapper you can do something like this

    @Override
    public void close() throws IOException {
        Throwable t = null;
        try {
            r1.close();
        } catch (Throwable t1) {
            t = t1;
            throw t1;
        } finally {
            if (t != null) {
                try {
                    r2.close();
                } catch (Throwable t2) {
                    t.addSuppressed(t2);
                }
            } else {
    
                r2.close();
            }
        }
    }
    

    Note:This will work because of precise rethrow feature in Java 7