try-with-resources fails to call close()

avidD picture avidD · Mar 26, 2015 · Viewed 14.2k times · Source

I am using the handy try-with-resources statement to close connections. This works great in most cases but only in one utterly simple method it does not work properly. Namely, here:

public boolean testConnection(SapConnection connection) {
  SapConnect connect = createConnection(connection);
  try ( SapApi sapApi = connect.connect() ) {
    return ( sapApi != null );
  } catch (JCoException e) {
    throw new UncheckedConnectionException("...", e);
  }
}

The sapApi object is non-null, the method returns true, but the close() method of sapApi is never called. I now resorted to use a finally block which works fine. But this is quite puzzling. The Java byte code also contains a call to close. Has anyone seen this behavior before?

Edit to clarify the situation:

This is the SapApi, it implements AutoCloseable, of course.

class SapApi implements AutoCloseable {

  @Override
  public void close() throws JCoException {
    connection.close(); // this line is not hit when leaving testConnection(..)
  }
..
}

The following is another method in the same class as testConnection(..). Here SapApi.close() is called before returning.

@Override
public List<Characteristic> selectCharacteristics(SapConnect aConnection,   InfoProvider aInfoProvider) {
  try (SapApi sapi = aConnection.connect()) {
    return sapi.getCharacteristics(aInfoProvider);
  } catch ( Exception e ) {
    throw new UncheckedConnectionException(e.getMessage(), e);
  }
}

Edit 2: This is SapConnect.connect():

SapApi connect() {
  try {
    ... // some setup of the connection
    return new SapApi(this); // single return statement
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

SapApi has no subclasses. There is just one implementation with the close method as above. In particular, there is no empty close().

Answer

Eyal picture Eyal · Mar 26, 2015

In order for close() to be called, SapApi must implement AutoCloseable interface, but since we are talking about connection, it is more appropriate that you SapApi will implement Closable interface which throws IOException.

Read this: http://tutorials.jenkov.com/java-exception-handling/try-with-resources.html