5

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().

Boghyon Hoffmann
  • 17,103
  • 12
  • 72
  • 170
avidD
  • 441
  • 1
  • 6
  • 16
  • 4
    In order for close() to be called, SapApi must implement Closeable interface, or at least implement java.lang.AutoCloseable. is that the situation? – Eyal Mar 26 '15 at 10:17
  • Isn't only AutoCloseable the one that is required? Closeable extends AutoCloseable. – laune Mar 26 '15 at 10:21
  • right, but AutoClosable is more generic (throws java.lang.Exception) and when talking about connections, Closable is more suitable since it throws IOException. – Eyal Mar 26 '15 at 10:27
  • Your code wouldn't compile, posibility #1: if `SapApi` implemented AutoCloseable, you would need to catch `IOException` (or your method would be declared with `throws IOException`). posibility #2: If `SapApi` didn't implement AutoCloseable, then the compiler would anyway complain, as only autocloseables are allowed in a try-catch with resources – morgano Mar 26 '15 at 10:34
  • AutoClosable throws Exception and not IOException, but you are right... – Eyal Mar 26 '15 at 11:03
  • Yes, SapApi implements Autocloseable. class SapApi implements AutoCloseable { ... @Override public void close() throws JCoException { connection.close(); } – avidD Mar 26 '15 at 11:19

3 Answers3

2

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

Eyal
  • 1,748
  • 2
  • 17
  • 31
  • SapApi implements AutoCloseable and its close method is called in other contexts in the same class. – avidD Mar 26 '15 at 11:23
1

I do not know what you mean by

This works great in most cases

1 That normally the SapApi is closed when used in try-with-resources

or

2 That it normally works for resources other than SapApi

I am answering on the assumption of number 2.

Try-with-resources will only work in Java 7 for resources that implement the AutoCloseable interface. So my first advice would be to for you to check the API for SapConnect and SapApi (whatever they are) to determine if that is the case.

APD
  • 1,459
  • 1
  • 13
  • 19
  • There are quite some methods in the same class that use the SapApi class in exactly the same expression (try-with-resources) where close() is properly called. Only for this one method it doesn't work. – avidD Mar 26 '15 at 11:22
0

One guess: maybe connect returns a child or proxy class of SapApi. With close overridden to do nothing if no change was made, only otherwise call super.close().

I'll give it as an answer, as AutoCloseable works even if no method is called.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138