1

Please take a look at the following DbUtil class example. Here are three its methods

public static void closeResults(ResultSet rs) {
    if (rs != null) {
        try {
            if (!rs.isClosed()){
                rs.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

public static void closeStatement(Statement stmt) {
    if(stmt != null) {
        try {
            if (!stmt.isClosed()) {
                stmt.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

public static void closeConnection(Connection conn) {
    if(conn != null) {
        try {
            if(!conn.isClosed()) {
                conn.close();    
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

As you can see all 3 methods have identical logic, and I would like to make this code DRY. A new common method can be written like this

public static void closeStatement(AutoCloseable ob) {
    if(ob != null) {
        try {
            ob.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

AutoCloseable interface doesn't contain isClosed method. But it is still a good practice (or even must do) to perform that check before trying to close a resource. Am I right? Can the code be simplified somehow and still perform isClosed check?

NOTE. This is just an example of the problem. I know that AutoCloseable interface is designed for try-with-resources technic and thus the code can be rewritten with that style and DbUtil won't be required anymore. But I would like to clarify for myself is it even possible to do something in a similar case. For example, I would think about creating some interface, say, MyAutoCloseable, extending AutoCloseable one and having isClosed method, but sure that won't work, because it wouldn't be possible to cast ResultSet or Statement to MyAutoCloseable.

humkins
  • 9,635
  • 11
  • 57
  • 75
  • 1
    you can do such things using reflection. but be carefull. java is designed to invoke methods on type you know they exists (because the compiler checks many things). using reflection, you break the compiler, you break encapsulation and many more things, and you will pay the cost one day. – spi Jul 14 '17 at 09:06
  • 1
    If you just want to use with these 3 objects, JavaDoc says: if the `close()` method is called on a closed object is, the call is a "no-op"... – Usagi Miyamoto Jul 14 '17 at 09:55

2 Answers2

1

You don't need to call isClosed() at all. Every close() method I have ever seen in the JDK for 20 years is idempotent, meaning you can call it twice or more without harm.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Except `AutoCloseable#close`. From the documentation:

    Note that unlike the {@link java.io.Closeable#close close} method of {@link java.io.Closeable}, this {@code close} method is not required to be idempotent. In other words, calling this {@code close} method more than once may have some visible side effect, unlike {@code Closeable.close} which is required to have no effect if called more than once.

    – humkins Jul 14 '17 at 10:34
  • But, finally, `AutoCloseable` was designed to be auto-closed, thus, obviously, it was not the best example in my question. – humkins Jul 14 '17 at 10:50
  • And all that would be obviated by using `Closeable`. – user207421 Jul 14 '17 at 10:51
0

You can achieve it using reflection.

public static void close(Object obj)
{
    try
    {
        Class<?> c = obj.getClass();
        Method isClosed = c.getDeclaredMethod("isClosed");// No I18N
        if( (Boolean)isClosed.invoke(obj) )
        {
            Method close = c.getDeclaredMethod("close");
            close.invoke(obj);
        }
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}
Cheran
  • 105
  • 1
  • 9