Search code examples
javajava-6

make code java 1.6 compatible (try-with-resources is not supported in -source 1.6)


I have the following code which is java 1.7 compatible, however, I need it to be compatible with java 1.6. currently I get the following error for this code: try-with-resources is not supported in -source 1.6

the code looks like this:

    try (QueryExecution qexec = QueryExecutionFactory.create(query, input.getModel())) {
        // Some other code
        while (results.hasNext()) {
            // do something
        }
        return something;
    }

what do I need to change in order to make it work with java 1.6?


Solution

  • The real answer:

    The real answer here is use Java 7 or 8. Java 6 is very old. Java 7 came out four years ago; Java 8, almost a year and a half.

    Only keep reading if there's a very, very good reason you can't do that. :-)

    TL;DR

    That specific example can be simply:

    QueryExecution qexec = QueryExecutionFactory.create(query, input.getModel());
    Throwable thrown = null;
    try {
        // Some other code
        while (results.hasNext()) {
            // do something
        }
        return something;
    }
    catch (Throwable t) {
        thrown = t; // Remember we're handling an exception
        throw t;
    }
    finally {
        try {
            qexec.close();
        }
        catch (Throwable t) {
            if (thrown == null) {
                // Not handling an exception, we can rethrow
                throw t;
            }
            else {
                // Log it or something, you can't allow it to
                // throw because there's *already* an exception
                // being thrown and you'll hide it. This is why
                // Java 7 added Throwable#addSuppressed.
            }
        }
    }
    

    But that's because it's a very simple case. If there were any other resources that needed closing (results, for instance?) or you were handling some exceptions in the code itself, it would be more complicated.

    The more general form is;

    SomeResource r1 = null;
    Throwable thrown = null;
    try {
        r1 = new SomeResource();
    
        SomeOtherResource r2 = null;
        try {
            r2 = new SomeOtherResource();
            // use them
            return something;
        }
        catch (Throwable t) {
            thrown = t; // Remember we're handling an exception
            throw t;
        }
        finally {
            try {
                r2.close();
            }
            catch (Throwable t) {
                if (thrown == null) {
                    // Not handling an exception, we can rethrow
                    throw t;
                }
                else {
                    // Log it or something, you can't allow it to
                    // throw because there's *already* an exception
                    // being thrown and you'll hide it. This is why
                    // Java 7 added Throwable#addSuppressed.
                }
            }
        }
    }
    catch (Throwable t) {
        thrown = t; // Remember we're handling an exception
        throw t;
    }
    finally {
        try {
            r1.close();
        }
        catch (Throwable t) {
            if (thrown == null) {
                // Not handling an exception, we can rethrow
                throw t;
            }
            else {
                // Log it or something
            }
        }
    }
    

    You'll probably want some utility library functions to help with this, it's a lot of boilerplate otherwise. I used to have things that did "silent" closes for the case where I knew an exception was already happening.


    Details: This is covered by §14.20.3 of the JLS and its subsections:

    A simple try-with-resources:

    try ({VariableModifier} R Identifier = Expression ...)
        Block
    

    translates to:

    {
        final {VariableModifierNoFinal} R Identifier = Expression;
        Throwable #primaryExc = null;
    
        try ResourceSpecification_tail
            Block
        catch (Throwable #t) {
            #primaryExc = #t;
            throw #t;
        } finally {
            if (Identifier != null) {
                if (#primaryExc != null) {
                    try {
                        Identifier.close();
                    } catch (Throwable #suppressedExc) {
                        #primaryExc.addSuppressed(#suppressedExc);
                    }
                } else {
                    Identifier.close();
                }
            }
        }
    }
    

    You'll have to remove the addSuppressed part as Throwable didn't have that in JDK6.

    An extended try-with-resources:

    try ResourceSpecification
        Block
    [Catches]
    [Finally]
    

    translates to:

    try {
        try ResourceSpecification
            Block
    }
    [Catches]
    [Finally]
    

    ...where that

    try ResourceSpecification
        Block
    

    ...is replaced by the big thing that the simple try-with-resources turns into, so the whole thing turns into:

    try {
        {
            final {VariableModifierNoFinal} R Identifier = Expression;
            Throwable #primaryExc = null;
    
            try ResourceSpecification_tail
                Block
            catch (Throwable #t) {
                #primaryExc = #t;
                throw #t;
            } finally {
                if (Identifier != null) {
                    if (#primaryExc != null) {
                        try {
                            Identifier.close();
                        } catch (Throwable #suppressedExc) {
                            #primaryExc.addSuppressed(#suppressedExc);
                        }
                    } else {
                        Identifier.close();
                    }
                }
            }
        }
    }
    [Catches]
    [Finally]
    

    ...which is why we love the try-with-resources statement so much.