0

Since JavaMail version 1.6.0 classes Store and Folder (amongst Transport) should implement AutoClosable interface.

I did not find any examples of someone using JavaMail API with auto-closable.

After a few tests I am not sure how to exactly use this feature as I have discovered a strange(?) behavior.

I am using the dependency com.sun.mail:javax.mail:1.6.0

@Test
public static void test() {
  Session session = ...;
  Intger countOfMessages;
  try(Store store = session.getStore("imap");) {
    store.connect("<host>", "<user>", "<password>");
    try(Folder folder = store.getFolder("inbox");) {
      folder.open(Folder.READ_ONLY);
      count = folder.getMessages().
    }
  }
  Assert.assertEquals(0, count);
}

So far everything works fine.

But if I change the name of the folder to some incorrect value (store.getFolder("_no_folder_with_this_name_")) then I get a

javax.mail.FolderNotFoundException: _no_folder_with_this_name_ not found

which is perfectly fine but this exception has a suppressed exception

Suppressed: java.lang.IllegalStateException: This operation is not allowed on a closed folder

I do see why this exception is thrown. The try(Folder folder = store.getFolder(...) throws the FolderNotFoundException, therefor the opening of the folder never happens and in the close method the folder is not open. But personally I would not expect this suppressed exception. As a second test I tried to leave the inner try block empty (try(Folder folder = store.getFolder("inbox");) {}) so that the folder is not going to be opened. Even in this situation the IllegalStateException is thrown.

Prior to version 1.6.0 I used a finally statement to close a folder by myself.

finally {
  if(folder != null) {
    try {
      if(folder.isOpen()) {
        folder.close(false);
      }
    }
    catch(MessagingException me) { LOG.warn(...); }
  if(store != null) {
    try {
      store.close();
    }
    catch(MessagingException me) { LOG.warn(...); }
  }
}

Am I doing something wrong or is this behavior a bug?

Filou
  • 490
  • 4
  • 17

1 Answers1

1

Try to restructure the code as:

@Test
public static void test() {
   Session session = ...;
   Intger countOfMessages;
   Store store = session.getStore("imap");
   store.connect("<host>", "<user>", "<password>");
   try (store) {   
   //try(Store s = store) //For pre JDK9
       Folder folder = store.getFolder("inbox");
       folder.open(Folder.READ_ONLY);
       try (folder) {
          count = folder.getMessages();
       }
   }
   Assert.assertEquals(0, count);
}

The close method balances with the connect and open. Calling getStore/getFolder doesn't mean there is an active connection. If would be cleaner if we made autoclosable calls less hostile.

jmehrens
  • 10,580
  • 1
  • 38
  • 47
  • I would love to have this less hostile in a future release. Your solution seems reasonable but I can not use it at the moment because of JDK-8's lack of support of variables in try-with-resource. – Filou Oct 12 '21 at 06:20
  • @Filou You can introduce a [new local](https://docs.oracle.com/en/java/javase/17/language/java-language-changes.html#GUID-015392DB-F5C4-4A8E-B190-E797707E7BFB) to make it compile. Also make sure your JavaMail is 1.6+ – jmehrens Oct 12 '21 at 14:04