try-with-resources не может вызвать close()

Я использую удобный оператор try-with-resources для закрытия соединений. Это отлично работает в большинстве случаев, но только в одном очень простом методе он не работает должным образом. А именно здесь:

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

Объект sapApi не равен нулю, метод возвращает true, но метод close() sapApi никогда не вызывается. Теперь я прибегнул к блоку finally, который отлично работает. Но это весьма озадачивает. Байт-код Java также содержит вызов закрытия. Кто-нибудь видел такое поведение раньше?

Изменить, чтобы прояснить ситуацию:

Это SapApi, он, конечно же, реализует AutoCloseable.

class SapApi implements AutoCloseable {

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

Ниже приведен еще один метод того же класса, что и testConnection(..). Здесь SapApi.close() вызывается перед возвратом.

@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);
  }
}

Редактировать 2: Это 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 не имеет подклассов. Существует только одна реализация с методом close, как указано выше. В частности, не существует пустой функции close().


person avidD    schedule 26.03.2015    source источник
comment
Для вызова close() SapApi должен реализовать интерфейс Closeable или, по крайней мере, реализовать java.lang.AutoCloseable. это ситуация?   -  person Eyal    schedule 26.03.2015
comment
Разве не требуется только AutoCloseable? Closeable расширяет AutoCloseable.   -  person laune    schedule 26.03.2015
comment
правильно, но AutoClosable является более общим (выдает java.lang.Exception), а когда речь идет о соединениях, Closable больше подходит, поскольку он выдает IOException.   -  person Eyal    schedule 26.03.2015
comment
Ваш код не будет компилироваться, возможность № 1: если SapApi реализует AutoCloseable, вам нужно будет поймать IOException (или ваш метод будет объявлен с throws IOException). возможность № 2: если бы SapApi не реализовал AutoCloseable, то компилятор все равно пожаловался бы, так как в try-catch с ресурсами разрешены только autocloseables   -  person morgano    schedule 26.03.2015
comment
AutoClosable выдает Exception, а не IOException, но вы правы...   -  person Eyal    schedule 26.03.2015
comment
Да, SapApi реализует Autocloseable. class SapApi реализует AutoCloseable { ... @Override public void close() throws JCoException { connection.close(); }   -  person avidD    schedule 26.03.2015


Ответы (3)


Для вызова close() SapApi должен реализовать интерфейс AutoCloseable, но, поскольку мы говорим о соединении, более уместно, чтобы SapApi реализовал интерфейс Closable, который генерирует IOException.

Прочитайте это: http://tutorials.jenkov.com/java-exception-handling/try-with-resources.html

person Eyal    schedule 26.03.2015
comment
SapApi реализует AutoCloseable, и его метод close вызывается в других контекстах того же класса. - person avidD; 26.03.2015

Я не знаю, что вы имеете в виду под

Это отлично работает в большинстве случаев

1 Обычно SapApi закрывается при использовании в try-with-resources

or

2 То, что это нормально работает для ресурсов, отличных от SapApi

Я отвечаю исходя из предположения № 2.

Try-with-resources будет работать только в Java 7 для ресурсов, реализующих AutoCloseable. Итак, мой первый совет: проверьте API для SapConnect и SapApi (какими бы они ни были), чтобы определить, так ли это.

person APD    schedule 26.03.2015
comment
В том же классе есть несколько методов, которые используют класс SapApi точно в том же выражении (try-with-resources), где правильно вызывается close(). Только для этого одного метода это не работает. - person avidD; 26.03.2015

Одно предположение: возможно, connect возвращает дочерний или прокси-класс SapApi. С переопределением close ничего не делать, если не было внесено никаких изменений, только в противном случае вызвать super.close().

Я приведу это как ответ, поскольку AutoCloseable работает, даже если метод не вызывается.

person Joop Eggen    schedule 26.03.2015