I am a dev with close to zero experience writing Java who currently works 
on a Kotlin web application that uses jOOQ - my first significant 
application in a JVM language. As such, I frequently find myself surprised 
when I encounter interfaces or behaviours in Java libraries that seen to 
make little sense from a Kotlin perspective. This message is about such an 
experience with jOOQ.

The Kotlin web application has a global exception handler; it has some 
special exception types that trigger special behavior in the global error 
handler; and at various places the application does stuff in transactions 
using code like this:

    dsl.transaction() { config -> 
        // Logic that might throw exceptions
    }

As it happens, some of the types of exception we have special handling for 
in the global error handler extend from `Exception`, while others extend 
from `RuntimeException` - a fact I was not especially conscious of and that 
is mostly of no significance in Kotlin, where unchecked exceptions don't 
exist and `throw Exception("some exception message")` is a perfectly 
acceptable idiom. Imagine my surprise, then, to discover that SOME of those 
special exceptions, if I throw them from within a 
`DSLContext.transaction()` callback, don't trigger their special behaviours 
in the global exception handler, which instead receives a 
DataAccessException. Some digging revealed that this code in 
`transactionResult0` was to blame, which handles exceptions of types that 
inherit from `RuntimeException` differently from those whose type inherits 
directly from `Exception` - specifically by wrapping the latter in a 
`DataAccessException` instead of rethrowing them directly:

    // [#6608] [#7167] Errors are no longer handled differently
    if (cause instanceof RuntimeException e)
        throw e;
    else if (cause instanceof Error e)
        throw e;
    else
        throw new DataAccessException(committed
            ? "Exception after commit"
            : "Rollback caused"
            , cause
        );

No doubt this behavior seems intuitive and reasonable to Java programmers, 
who work in a world with checked exceptions. To a dev using jOOQ from 
Kotlin and unfamiliar with Java, though, it felt rather like an arbitrary 
trap that didn't need to exist, and my first instinct was to file a bug 
report. After all, jOOQ officially supports Kotlin, so shouldn't it refrain 
from doing this arbitrary wrapping of (some) exceptions that has no reason 
to happen from a Kotlin perspective?

On reflection, though, I'm struggling to figure out how I ought to feel 
about this. What's the "correct" behavior for jOOQ to have here? Should 
anything change?

I thought for a while about whether jOOQ should behave differently when 
being used "from Kotlin" than when being used "from Java", but I think that 
- given that Java code can call functions defined Kotlin code that calls 
functions defined in Java code and so on ad infinitum - the very concept of 
jOOQ being used "from Kotlin" or "from Java" is probably too ill-defined 
for this to make sense. Doing something like having behavior change based 
on the inclusion of the jOOQ-kotlin package also seems like a disgusting 
trap in its own right.

That leaves me with a couple of thoughts on things that jOOQ could do that 
might be good ideas:

1. Maybe that block I quoted above should just unconditionally throw `e`? 
Obviously just `throw e` won't even compile, but there are hacks (see e.g. 
https://stackoverflow.com/q/31316581/1709587) to let you throw exceptions 
of checked types without listing them in a `throws` clause in the method 
declaration, so it is at least POSSIBLE for jOOQ to behave this way. 
Ignoring backwards compatibility, would this indeed be the better behavior 
for jOOQ to have? If so, is it worth breaking backwards compatibility over?

2. Maybe having some Kotlin-specific alternative to 
`DSLContext.transaction` (and whatever other methods are affected by this 
same issue) in jOOQ-kotlin? This could probably be a simple wrapper around 
`DSLContext.transaction` that "unwraps" exceptions that are wrapped in 
`DataAccessException`.

Alternatively, perhaps the right perspective on this is that we Kotlin 
programmers are newcomers in Java lands, and need to assimilate into the 
local culture - including understanding Java practices like handling 
Exceptions and RuntimeExceptions differently, and anticipating their use. 
>From this perspective, perhaps jOOQ is doing nothing wrong or ill-advised 
whatsoever, and I've simply learned a necessary lesson about Java. 
Certainly a workaround is possible: I can implement the wrapper around 
`DSLContext.transaction` that I contemplated above in my application and 
use it instead of using `DSLContext.transaction` directly.

What's the right way to think about this, do you reckon? Should anything in 
jOOQ change?

Cheers,
Mark

-- 
You received this message because you are subscribed to the Google Groups "jOOQ 
User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jooq-user/c7a318bb-4f76-4734-ba2a-eb5afba20533n%40googlegroups.com.

Reply via email to