Never forget to call .execute () in jOOQ – Java, SQL and jOOQ again.


JOOQ’s DSL, like any fluid API, has a big caveat. It’s very easy to forget to call .execute(). And when you do, there’s a good chance you’ll be staring at your code for minutes, because everything looks perfect:

ctx.insertInto(T)
   .columns(T.A, T.B)
   .values(1, 2);

Fix … fix … fix … Why doesn’t he insert this line?

“Aaaah, not yet !!”

This is how it’s done:

ctx.insertInto(T)
   .columns(T.A, T.B)
   .values(1, 2)
   .execute();

In principle, this kind of error can happen with any smooth API. for example StringBuilder

sb.append("a").append("b"); // Not consuming the result

Or flow:

Stream.of(1, 2).peek(System.out::println); // Not so much peeking

But this usually doesn’t happen as much, because the difference with jOOQ is that

  • jOOQ’s DML statements (INSERT, UPDATE, DELETE, MERGE) and DDL statements (CREATE, ALTER, DROP, TRUNCATE), and some other products a side effect
  • This side effect is the only thing that interests us. The result (the number of updates) is usually irrelevant

And as such, we don’t care about the outcome of execute(), which is a int. No one forgets to call fetch() on a jOOQ ResultQuery:

ctx.select(T.A, T.B)
   .from(T); // Well duh

Because without calling fetch() or something similar, we don’t get any results, and we want the results, just like with the StringBuilder or the Stream. But we don’t want that execute() result.

As such, even we, when writing the integration tests for jOOQ, sometimes forget to call this silly little method.

No more!

When it happened again this week …

… I finally created a problem to think about it: https://github.com/jOOQ/jOOQ/issues/11718. And I created a problem to ask if JetBrains could do something about it: https://youtrack.jetbrains.com/issue/IDEA-265263

And they already can! Separated from org.jetbrains.annotations.Contract annotation, which is there precisely for this reason, apparently it is also possible to imitate the JSR-305 @CheckReturnValue annotation on each method “whose return value must be checked” (ie a method which has no side effect, or whose side effect is to mutate only “this“).

I added this annotation, added it to all relevant jOOQ APIs, which was a bit of a yak shave (https://github.com/jOOQ/jOOQ/commit/f2b529a2305f8c5f8d037776687887a5acd50b11) and there you go

As you can see, IntelliJ now warns the user whenever they forget to consume the result of any of the DSL methods of jOOQ (by calling execute(), passing it to a method that consumes it, etc.)

Thanks again to Tagir Valeev from JetBrains for guiding me through this and even improving the @Contract annotation, which jOOQ could use in a future version.





Source link

Leave a Reply

Your email address will not be published. Required fields are marked *