question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Evaluating JDBI. Why use `Closeable` on objects that are returned to the user that are not supposed to be closed?

See original GitHub issue

So, after just 30 minutes of evaluating JDBI, I ran into this issue that I think will deter me from using it.

I want to do the following:

jdbi.useTransaction(handle -> {
    handle.createUpdate("INSERT INTO xyz (data) VALUES (:data)")
        .bind("data", data)
        .execute();
});

Now, createUpdate returns a Closeable. My question is, why would it do this when there is no need to create the actual closeable resource until one of execute or one is called? You are basically giving me a simple “binder” type object that allows me to bind things to a simple String, but it seems this object that is returned is already an “expensive” resource (perhaps there is even an actual prepared statement created already) that will require closing. Why not defer creating the prepared statement until it is actually required?

Now the user is getting a warning on createUpdate that this resource needs closing, and IMHO these warnings should not be ignored without good reason. Note that in this scenario, the user never needs to close anything, so why return something that is Closeable in the first place?

I would expect the implementation of createUpdate to be something like:

  class Handle {
       UpdateBinder createUpdate(String sql) {
            return new Binder(this, sql);  // this = Handle     
       }
  }

  class UpdateBinder {  // not Closeable, why would it be?
       UpdateBinder (Handle handle, String sql) {
            ...
       }

       ... bind methods ...

       int execute() {
            // - use handle to create prepared statement -- use try with resources on that
            // - bind everything
            // - execute
            // - close
       }
  }

No Closeable is ever returned to the user.

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:1
  • Comments:13 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
hgschmiecommented, Oct 7, 2022

I am planning to add documentation that describes this resource management requirement and make sure that JDBI users are more aware.

The good (?) news is that most people use the standard semantics of handle.create<something>.bind(...).map(...).one()/list()/any method from ResultIterable that is not stream()/iterator() and that stanza is managing the resources for the user.

The only exception are stream() and iterator() because they maintain state within the iterator/stream.

I agree that implementing (Auto)Closeable on all statements because of this one use case may be overkill. However, we many need to stress that whenever an iterator or a stream is used with JDBI, they must be wrapped in try-with-resources (or manually closed), because otherwise JDBI will leak resources.

This may be especially critical for streams where a map or filter function throws an exception.

1reaction
hjohncommented, Oct 1, 2022

Cool. This is interesting. What IDE are you using? This error dialog is not immediately familiar. I would love to try that out.

This is Eclipse, with the warnings “Resource Leak” and “Potential Resource Leak” activated (under Window > Preferences > Java > Compiler > Error/Warnings > Potential Programming Problems).

IntelliJ may have something similar under “Resource Management” (AutoCloseable used without try with resources).

For the basic pattern where it shows this problem, all the resource management should be done by JDBI. I am curious to see why the IDE thinks that the resources would be leaking.

If you return something that is AutoCloseable anywhere to user space, and its not closed by the user, then its considered a leak – it’s not possible for the IDE to analyze if it was closed by another follow up call.

I think that returning AutoCloseable indicates that it should be used in try with resources (if at all possible of course). If this code makes no sense:

  try(Update u = handle.createUpdate("<sql>")) {
        u.execute();
  }

…then the closeable is returned at the wrong place. I indeed think it makes no sense here, as there is nothing that should be closed in this case.

I tried this test:

    @Test
    public void testLeakage() {
        Jdbi jdbi = h2Extension.getJdbi();

        String data = "foo";
        jdbi.useTransaction(handle -> {
            handle.createUpdate("INSERT INTO something (name) VALUES (:data)")
                .bind("data", data)
                .execute();
        });
    }

and at least intellij (which is pretty good at figuring out resource leaks) does not complain. I would love to try with your IDE as well.

It’s not strictly a leak though (although not even IntelliJ will be able to figure that out), more that a closeable is returned at a point where there isn’t actually anything that needs closing yet. Eclipse flags it as a “potential” leak, but in general, that’s still a very good warning (it never occurs in “regular” code aside from the odd unit test, and I always have this on). IDE’s will flag it as something that needs closing, but if there was nothing that needed closing then the returned object is incorrect to implement closeable.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Jdbi 3 Developer Guide
These methods use callbacks and provide a fully managed handle that is correctly closed and all related resources are released. withHandle allows the...
Read more >
Jdbi transaction - multiple methods - Resources should be ...
I disagree this is good behavior. The object returned from createUpdate shouldn't be Closeable if it doesn't need to be closed by the...
Read more >
jdbi - Bountysource
jDBI is designed to provide convenient tabular data access in Java(tm). ... Why use `Closeable` on objects that are returned to the user...
Read more >
Implementing AutoCloseable or Closeable - Google Groups
A new interface called java.lang.AutoCloseable was introduced in Java SE 7. All it does is provide a void method named close() that may...
Read more >
Returning a ResultIterator from a method using getHandle ...
SQLException: Operation not allowed after ResultSet closed at ... This usage is no longer supported for on-demand SQL objects.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found