In Java, how to check that AutoCloseable.close() has been called?

前端 未结 5 519
忘了有多久
忘了有多久 2021-02-01 03:38

I am authoring a java library. Some of the classes that are meant to be used by library users, hold native system resources (over JNI). I\'d like to ensure that the user \"dispo

5条回答
  •  南笙
    南笙 (楼主)
    2021-02-01 04:07

    In general, if you could reliably test whether a resource has been closed, you could just close it yourself.

    The first thing to do is to make handling resource easy for the client. Use the Execute Around idiom.

    As far as I know, the only use of execute around for resource handling in the Java library is java.security.AccessController.doPrivileged and that's special (the resource is a magic stack frame, that you really don't want to leave open). I believe Spring has long had a much-needed JDBC library for this. I was certainly using execute-around (didn't know it was called that at the time) for JDBC shortly after Java 1.1 made it vaguely practical.

    The library code should look something like:

    @FunctionalInterface
    public interface WithMyResource {
        R use(MyResource resource) throws MyException;
    }
    public class MyContext {
    // ...
        public  R doAction(Arg arg, WithMyResource with) throws MyException {
            try (MyResource resource = acquire(arg)) {
                return with.use(resource);
            }
        }
    

    (Do get the type parameter declarations in the right place.)

    Client side usage looks something like:

    MyType myResult = yourContext.doContext(resource -> {
        ...blah...;
        return ...thing...;
    });
    

    Back to testing. How do we make it easy to test even if the testee exfiltrates the resource from the execute around or some other mechanism is available?

    The obvious answer is that you provide the execute around solution to the test. You will need to provide some execute around-using API to verify all of your resources that have been acquired in the scope have also been closed. This should be paired with the context the resource is acquired from rather than using global state.

    Depending upon which testing framework your clients are using, you may be able to offer something better. JUnit5, for instance, has an annotation-based extension facility which allows you to supply the context as an argument and also apply checks after each test has executed. (But I haven't used it much, so I'm not going to say anything more.)

提交回复
热议问题