3

I'm running into an issue similar to this one, except with java.util.Scanner. I have this static method:

public static void close(final Closeable c) {
    if(c != null) {
        Log.debug(TAG, "instance of " + c.getClass().getName());
        try {
            c.close();
        } catch (IOException e) {
            // ignore
        }
    }
}

When passed a Scanner on API 15, it crashes like so:

08-29 20:33:42.979: E/AndroidRuntime(2245): FATAL EXCEPTION: main
08-29 20:33:42.979: E/AndroidRuntime(2245): java.lang.IncompatibleClassChangeError: interface not implemented
08-29 20:33:42.979: E/AndroidRuntime(2245):     at com.mycompany.myapp.IOUtil.close(IOUtil.java:36)
[more lines omitted]

The docs say that Scanner implements Closeable even if you set the doc API level below 15. Could this be a vendor-specific issue? I only have one API 15 device to test on, and nothing between that and API 19, which works fine.

Community
  • 1
  • 1
Kevin Krumwiede
  • 9,868
  • 4
  • 34
  • 82

2 Answers2

0

Not a direct answer to my question, but in light of Derek Fung's answer, my close() method now looks like this:

public static void close(final Closeable c) {
    if(c != null) {
        /* Several classes that were made Closeable in Java 1.7 also
         * became Closeable in Android API 19, including java.net.Socket
         * and java.util.Scanner.  The fact that the minimum SDK version
         * is lower than that does not cause a compiler error when objects
         * of those types are passed to this method, resulting in a
         * IncompatibleClassChangeError at runtime.  Hence this seemingly
         * pointless test. */
        if(c instanceof Closeable) {
            try {
                c.close();
            } catch (IOException e) {
                // ignore
            }
        }
        else {
            Log.debug(TAG, c.getClass().getName() + " does not implement Closeable; attempting reflection");
            try {
                final Method m = c.getClass().getMethod("close");
                m.invoke(c);
            }
            catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException e) {
                // shouldn't happen
                Log.warn(TAG, "could not close " + c.getClass().getName(), e);
            } catch (InvocationTargetException e) {
                // ignore
            }
        }
    }
}

The reflection code is executed and seems to work fine on API 15.

Kevin Krumwiede
  • 9,868
  • 4
  • 34
  • 82