[REQUEST FOR FEEDBACK] Handling of NULL in jOOQ's comparison predicates

605 views
Skip to first unread message

Lukas Eder

unread,
Dec 12, 2012, 3:06:48 PM12/12/12
to jooq...@googlegroups.com
Hello group

I have received interesting feedback about jOOQ's handling of NULL in comparison predicates. This is about a user who uses jOOQ for SQL rendering. They use jOOQ's support for named parameters as documented in the manual, here:

The issue can be seen here:

As some of you may be aware of, the jOOQ .equal() and .notEqual() methods have a "special" behaviour, when passing a Java null value. This is documented in the Javadoc:

If value == null, then this will return a condition equivalent to isNull() for convenience. SQL's ternary NULL logic is rarely of use for Java programmers.

Taken from:

Now, while this may be quite convenient, as in 80% of the use cases, users really don't want to deal with SQL's ternary NULL/UNKNOWN logic, it can cause quite some confusion when users actually want to extract SQL and bind values from jOOQ queries, as jOOQ is then "swallowing" these particular null bind values.

My questions to the group:
  1. Do you find this "feature" really useful (as opposed to doing null checks and handling IS NULL manually)? Or do you think it should be removed?
  2. Do you think a new Setting should be introduced to allow for distinguishing the two use-cases for jOOQ? (my favourite option, so far, even if I don't like adding to many settings)
  3. Do you see any other solution to deal with the problem?
Thanks for any feedback!

Cheers
Lukas

Durchholz, Joachim

unread,
Dec 13, 2012, 5:32:46 AM12/13/12
to jooq...@googlegroups.com
I have use cases for both "null-safe" (binary) and ternary logic.
 
The problem with ternary logic is that it's quite unintuitive unless your intuition is full SQL.
I.e. people who think SQL will want the ternary logic as default, people who think Java will want the null-safe (binary) logic as default.
Jooq being a Java library should go with Java conventions. However, it would be useful to have alternate predicates that employ ternary logic, i.e. equal3 and notEqual3 (which would need to return TRUE/FALSE/UNKNOWN so you can have and3, or3, not3 etc.).

From: jooq...@googlegroups.com [mailto:jooq...@googlegroups.com] On Behalf Of Lukas Eder
Sent: Wednesday, December 12, 2012 9:07 PM
To: jooq...@googlegroups.com
Subject: [REQUEST FOR FEEDBACK] Handling of NULL in jOOQ's comparison predicates

Lukas Eder

unread,
Dec 13, 2012, 6:19:42 AM12/13/12
to jooq...@googlegroups.com
Hi Joachim

Thanks for sharing your thoughts

> However, it would
> be useful to have alternate predicates that employ ternary logic, i.e.
> equal3 and notEqual3 (which would need to return TRUE/FALSE/UNKNOWN so you
> can have and3, or3, not3 etc.).

Yes, that's another option, to just "overload" the actual methods in
order to force ternary logic to be rendered. This might be better than
introducing a new setting for two reasons:

1. Settings are always obscure
2. Settings are global to a query. You cannot mix behaviour within a
query, then.

Right now, only equal/eq and notEqual/ne are affected from this (Java
way of thinking) feature. Other methods behave in the SQL way, i.e. as
you put it, "and" is in fact "and3"

Maybe the whole jOOQ API could be reviewed for applicability of a
distinction between ternary SQL logic and "Java" logic

Cheers
Lukas

Durchholz, Joachim

unread,
Dec 13, 2012, 6:37:59 AM12/13/12
to jooq...@googlegroups.com
> This might be better than introducing a new setting for two reasons:
>
> 1. Settings are always obscure
> 2. Settings are global to a query. You cannot mix behaviour within a query, then.

Yep, a per-query setting would be bad. Sometimes you want binary and ternary logic within the same query.

> Right now, only equal/eq and notEqual/ne are affected from this
> (Java way of thinking) feature. Other methods behave in the SQL way,
> i.e. as you put it, "and" is in fact "and3"

Well, as long as the primitives are binary, this doesn't matter.
So I guess the logical operators (and, or, not) don't need a binary-vs-ternary distinction after all.

> Maybe the whole jOOQ API could be reviewed for applicability of
> a distinction between ternary SQL logic and "Java" logic

That would certainly be good.

Some thoughts for that avenue, probably incomplete, in no particular order:

Ternary logic and/or/not is compatible with binary, no separate API required.
Aggregate functions generally ignore nulls. I can't think of a binary-vs-ternary semantic distinction that would make any sense, so that part of the API can be left as is.
I'm not sure about IN and NOT IN (I have no idea what a typical database does if the set of values contains a NULL).
Ordered comparisons ( < > BETWEEN ) against NULLs tend to have three variants: UNKNOWN, NULLS FIRST, NULLS LAST.
Not sure how to deal with user-defined functions. Probably nothing can be done. Maybe there isn't an issue anyway.

Lukas Eder

unread,
Dec 13, 2012, 10:42:11 AM12/13/12
to jooq...@googlegroups.com
> Ternary logic and/or/not is compatible with binary, no separate API required.

Hmm, as a matter of fact, SQL:2008 specifies the following truth tables:

Table 11 — Truth table for the AND boolean operator
AND     True    False Unknown
True    True    False Unknown
False   False   False False
Unknown Unknown False Unknown

Table 12 — Truth table for the OR boolean operator
OR      True  False   Unknown
True    True  True    True
False   True  False   Unknown
Unknown True  Unknown Unknown

Table 13 — Truth table for the IS boolean operator
IS      TRUE  FALSE UNKNOWN
True    True  False False
False   False True  False
Unknown False False True


So, there really is some consideration to be done in that area as well... However, not all databases actually implement the boolean data type, so for many databases, the above table doesn't really apply


> Aggregate functions generally ignore nulls. I can't think of a binary-vs-ternary semantic distinction that would make any sense, so that part of the API can be left as is.

It could be relevant to GROUP_CONCAT(), LISTAGG() and similar (ordered) aggregate functions.

> I'm not sure about IN and NOT IN (I have no idea what a typical database does if the set of values contains a NULL).

Yes, NOT IN is the most tricky one. 1 NOT IN (NULL, 1) returns false (or more correctly, returns NULL). I had recently posted a blog post about this, and how it isn't handled correctly (the ternary way) in all databases:

As soon as you have NULL in the right hand side of the NOT IN predicate, you'll always get NULL as a result. For the IN predicate, however, NULL is irrelevant.

> Ordered comparisons ( < > BETWEEN ) against NULLs tend to have three variants: UNKNOWN, NULLS FIRST, NULLS LAST.

Same here. I'm pretty sure, the SQL standard defines UNKNWON to be the only correct outcome of such comparisons. But some databases may have different views on the subject.

> Not sure how to deal with user-defined functions. Probably nothing can be done. Maybe there isn't an issue anyway.

Yes, I don't think there's an issue here.

Thanks for your thoughts. I'll do some thinking on my side, too.

Durchholz, Joachim

unread,
Dec 13, 2012, 11:28:38 AM12/13/12
to jooq...@googlegroups.com
> However, not all databases actually implement the boolean
> data type, so for many databases, the above table doesn't
> really apply

You can't simply output the result of a boolean expression, but you can always extract them via CASE expressions, so yes the truth tables do apply.
It's just that if you input

>> Aggregate functions generally ignore nulls. I can't think
>> of a binary-vs-ternary semantic distinction that would
>> make any sense, so that part of the API can be left as is.
>
> It could be relevant to GROUP_CONCAT(), LISTAGG() and similar
> (ordered) aggregate functions.

Agreed. Needs checking.
In those cases where having a NULL is equivalent to not having a row, no ternary variant is needed.

>> I'm not sure about IN and NOT IN (I have no idea what a
>> typical database does if the set of values contains a NULL).
>
> Yes, NOT IN is the most tricky one. 1 NOT IN (NULL, 1)
> returns false (or more correctly, returns NULL).

Actually "1 not in (NULL, 1)" returns FALSE.
You can test that by wrapping the condition in a NOT: For NULL (UNKNOWN for conditions), NOT does not change the outcome, for FALSE, you get TRUE.
So "select * from dual where not (1 not in (null, 1))" returns all rows of the DUAL table.

That's semantically sound actually. NULL stands for an indefinite value, so 1 is in (NULL, 1) however you vary the NULL, which means that 1 NOT IN (NULL, 1) should return FALSE, not UNKNOWN.

> I had recently posted a blog post about this, and how it
> isn't handled correctly (the ternary way) in all databases:
> http://blog.jooq.org/2012/01/27/sql-incompatibilities-not-in-and-null-values/

Heh.
Did I mention that ternary logic is unintuitive? ;-)
I guess that should be expanded with "... even for RDBMS experts."

>> Ordered comparisons ( < > BETWEEN ) against NULLs tend to
>> have three variants: UNKNOWN, NULLS FIRST, NULLS LAST.
>
> Same here. I'm pretty sure, the SQL standard defines UNKNWON to
> be the only correct outcome of such comparisons.
> But some databases may have different views on the subject.

I was more after "what would a developer need".
This was inspired by NULLS FIRST/LAST in ORDER BY clauses, but of course if you have a comparison in a WHERE condition, the outcome of < or > will always be UNKNOWN.
It would be useful to build a code generator that emits code for, say, a NULLS FIRST <.
However, I guess that's beyond the scope of what Jooq should do. A Java-side lessNullsFirst(a, b) would probably have to emit something like
(a is null or b is not null and a < b)
(untested, likely buggy), and that means emitting the subexpression for a and b twice - you don't even want to have that generated if when it's useful.

> Thanks for your thoughts. I'll do some thinking on my side, too.

You're welcome.
It's always nice to be heard :-)

Stéphane Cl

unread,
Dec 17, 2012, 3:04:47 AM12/17/12
to jooq...@googlegroups.com
Hello,

I probably haven't considered all the possible cases because I rarely use IS NULL. When dealing with dynamic SQL, the code behind a typical "search window" is more like :

if( StringUtils.isBotBlank( field.getText() ) )
       //add condition on column
else
       //do nothing (no null logic)

In case you need to write a DAO method that can match some column against multiple values, null included, and don't want too much if-else logic, you could use IS NOT DISTINCT FROM which works well with NULL.
I'd say it's not that bad the way it is now as I am not aware of any valid use for a "column = null" predicate. Moreover, it seems that jdbc itself tends to translate java null to SQL NULL with some horrible side effects like

Long longValue = null;
stmt.setLong( longValue ); //NPE because it calls setLong(long) due to autoboxing

but honestly, I'd choose to use isNull anyway before relying on any kind of special treatement of NULL on the API side. Jooq makes dynamic where clauses very easy to write so I'd say it doesn't hurt to write a pair of if-else to decide between isNull or Equal and be 100% safe.

Another possibility would be to use a dedicated constand, like c# DbNull that can be easily differentiated...

T_BOOK.idAuthor.eq( DB_NULL )

but it would almost certainly cause headaches with generic parameters for little gain.

So in order of preference I'd say
1) Remove it if possible, one of the biggest strength of jooq resides in its SQL-centric DSL that lets you guess the corresponding query without obscure alteration. 
2) Keep it the way it is now, after all it would make things backward compatible and it's probably not used that often
3) As a last resort, add the boolean flag but imho configurable APIs tend to become inelegant and confusing (Java SAX parsers are good examples).


Best

Durchholz, Joachim

unread,
Dec 17, 2012, 5:51:26 AM12/17/12
to jooq...@googlegroups.com
> I probably haven't considered all the possible cases because I rarely
> use IS NULL. When dealing with dynamic SQL, the code behind a typical
> "search window" is more like :
>
> if( StringUtils.isBotBlank( field.getText() ) )
> //add condition on column
> else
> //do nothing (no null logic)

That's the simple SQL uses. However, more advanced uses tend to turn that perspective into an unavailable luxury.

Once you start writing outer joins, null handling becomes really important. For example, to test whether a relationship exists, you can test any primary key column: if it's null, the corresponding related record didn't exist.
This isn't important when doing interactive SQL but quite common in batch processing, where you try to shove as much work as possible into the query optimizer.

The other usage is where a null value has a real semantics, different from that of an empty string or a zero value.
In fact, I have several fields where zero means "upper limit is zero, i.e. don't allow anything", and null is "no upper limit, i.e. allow anything" (quantities to purchase, in this case).
I even built a JTextField descendant that clearly differentiates between the two, and shows a different representation for a null value if it doesn't have focus.

For strings, the difference between null and an empty string isn't so easy to represent and in fact rarely if ever needed.
In those cases where I do have a nullable string fields, it's always been an enumeration, and these I'm converting between DB representation and screen representation anyway.

Stéphane Cl

unread,
Dec 17, 2012, 7:23:22 AM12/17/12
to jooq...@googlegroups.com
Dear Joachim,
I think you misunderstood my post

That's the simple SQL uses. However, more advanced uses tend to turn that perspective into an unavailable luxury.

Once you start writing outer joins, null handling becomes really important. For example, to test whether a relationship exists, you can test any primary key column: if it's null, the corresponding related record didn't exist.
This isn't important when doing interactive SQL but quite common in batch processing, where you try to shove as much work as possible into the query optimizer.


Of course, I am not discussing whether testing columns for NULL makes sense or not because I know it *does* have its use. I was asking myself if there were use cases in which translating java code such as "field.eq( null)" to "field IS NULL" was a real gain. My personal answer is "no" because I rarely need to mix both.   

In a typical DAO method like findCustomerByCriteria( String name, Integer idGroup, String countryCode  ... ), (such as the first snippet you quoted), passing "idGroup = Null" in parameter I'd expect the query to ignore the group filter, not to search for customers having no group. 
In case I'd really need to search for null explicitly, a simple if (idGroup == null) { //use field.isNull() } else {//use field.eq} would not be a big deal. I don't many examples where you'd take advantage of translating =NULL to IS NULL automatically.  

 
The other usage is where a null value has a real semantics, different from that of an empty string or a zero value.
In fact, I have several fields where zero means "upper limit is zero, i.e. don't allow anything", and null is "no upper limit, i.e. allow anything" (quantities to purchase, in this case).
I even built a JTextField descendant that clearly differentiates between the two, and shows a different representation for a null value if it doesn't have focus.


Here again, I am not saying that NULLs have no use. My point is entirely at the API level.
In you upper limit example, the fact that you wrote a special widget for your nullable upper limit field is a good indicator that properly handling NULL needs separate code. As a result, you probably don't really benefit from an API mixing both cases. 
You would not consider the absence of input in your GUI as the result of an end-user wanting to list all products without a purchase limit, so you can't just send the raw input directly from your GUI to a select query saying "Oh yeah, jooq will translate this =NULL to IS NULL"  ? You'd use a dedicated field or a checkbox for this and some logic to decide if you need to check for null OR match a value.  

Imho, there aren't many use cases where you can make your life easier by automatically transforming eq(null) to IS NULL, a NULL in a column is rarely just a value like any other, rather a special case.like for example the absence of a value. So it's pretty rare that you can use the same code for selecting, filtering etc...

 
For strings, the difference between null and an empty string isn't so easy to represent and in fact rarely if ever needed.
In those cases where I do have a nullable string fields, it's always been an enumeration, and these I'm converting between DB representation and screen representation anyway.

Totally agreed, I heard that in the past, using NULLs people were using nulls to save disk space, but considering space availability and optimizations made to rdbms, I don't think it's relevant nowadays.

Lukas Eder

unread,
Dec 17, 2012, 2:20:43 PM12/17/12
to jooq...@googlegroups.com
Joachim, Stéphane,

Thank you very much for your valuable input and for sharing your
reasoning. I entirely agree with this paragraph by Stéphane:

> Stéphane:
> --------------
> In you upper limit example, the fact that you wrote a special widget for
> your nullable upper limit field is a good indicator that properly handling
> NULL needs separate code. As a result, you probably don't really benefit
> from an API mixing both cases. [...]

Indeed, when dealing with NULL as a "special value", you will probably
have to resort to "special logic" - no matter whether you understand
that "specialty" in the Java way (no value), or in the SQL way (an
unknown value).

However, remember that jOOQ's current implementation of handling
"eq(null)" predicates as if they were "IS NULL" predicates originates
from the fact that a true "X = NULL" or "X <> NULL" comparison
predicate is hardly of any use, even to those SQL aficionados that
want to implement ternary logic.

> Stéphane:
> --------------
> Imho, there aren't many use cases where you can make your life easier by
> automatically transforming eq(null) to IS NULL, a NULL in a column is rarely
> just a value like any other, rather a special case.like for example the
> absence of a value. So it's pretty rare that you can use the same code for
> selecting, filtering etc...

The most important use case that lead to the current implementation in
jOOQ are filters for optional foreign keys. In that case, Java's null
and SQL's NULL usually share the same semantics in that SQL's NULL
doesn't represent UNKNOWN, but "no value". But then again, as Stéphane
suggested, a Java "null" value for such a filter probably indicates
"no filter", rather than a filter for "no reference". In other words,
even if BOOK.AUTHOR_ID is nullable, a null Java filter reference would
probably indicate "all books", rather than "books with no author"

> Joachim
> ------------
> Once you start writing outer joins, null handling becomes
> really important. For example, to test whether a relationship
> exists, you can test any primary key column: if it's null,
> the corresponding related record didn't exist. This isn't
> important when doing interactive SQL but quite common
> in batch processing, where you try to shove as much work
> as possible into the query optimizer.

I'm guessing that you're hinting at writing a NOT EXISTS anti-join
using OUTER JOIN and IS NULL predicates? In that case, you should
really explicitly use an IS NULL predicate via FIELD.isNull(), instead
of relying on some jOOQ voodoo using FIELD.eq(null) if it's only to
clearly show your intent.

> Stéphane:
> --------------
> Another possibility would be to use a dedicated
> constand, like c# DbNull that can be easily differentiated...

> T_BOOK.idAuthor.eq( DB_NULL )

A DB_NULL constant would "consume" a value in the Java world, to
actually represent that null value. A possible value for integers
would be Integer.MIN_VALUE, Long.MIN_VALUE. This is quite problematic
for byte and short though. "Wasting" Byte.MIN_VALUE for such a special
semantic seems wrong / surprising to me. Or did I miss something from
C# DB_NULL?

From these discussions and also your input, I think jOOQ 3.0 should
introduce a slight backwards-incompatibility of behaviour in the eq()
/ equals() / ne() / notEquals() methods, and remove this "feature" for
these reasons:

1. It is surprising to some users, and thus "voodoo". Voodoo is never good.
2. It is not entirely reliable when extracting bind values from jOOQ,
thus the original GitHub issue
https://github.com/jOOQ/jOOQ/issues/2001. Without removing the current
feature, this issue is hard to fix and it was brought up several times
on this list.
3. Its implementation is a kludge (isNullLiteral()). Removing this
implementation would greatly improve the code base
4. Those few users that might rely on this feature can live with
writing if / else checks as suggested in this thread.
5. jOOQ already supports the DISTINCT predicate (IS [NOT] DISTINCT
FROM), which is the correct SQL way of doing NULL-agnostic checks

Again, thanks for your inputs. In a second step (after removing this
feature), I will again review the API to see if any other parts should
be adapted for ternary logic.

Cheers
Lukas

Lukas Eder

unread,
Dec 17, 2012, 2:27:03 PM12/17/12
to jooq...@googlegroups.com
> 1. It is surprising to some users, and thus "voodoo". Voodoo is never good.
> 2. It is not entirely reliable when extracting bind values from jOOQ,
> thus the original GitHub issue
> https://github.com/jOOQ/jOOQ/issues/2001. Without removing the current
> feature, this issue is hard to fix and it was brought up several times
> on this list.
> 3. Its implementation is a kludge (isNullLiteral()). Removing this
> implementation would greatly improve the code base
> 4. Those few users that might rely on this feature can live with
> writing if / else checks as suggested in this thread.
> 5. jOOQ already supports the DISTINCT predicate (IS [NOT] DISTINCT
> FROM), which is the correct SQL way of doing NULL-agnostic checks

... not to forget:

6. The current implementation of eq/equal/ne/notEqual is inconsistent
with [NOT] IN, [NOT] BETWEEN, gt/ge/lt/le and various other
predicates.

Stéphane Cl

unread,
Dec 19, 2012, 3:06:15 AM12/19/12
to jooq...@googlegroups.com
Hi Lukas,
You are the one who deserves thanks.
I guess you're making the best decision. It's a short-term sacrifice for a long term gain. I think developers tend to put too much effort on keeping things backward compatible and sometimes that's at the expense of quality at the end of the day. It is a hot debate in the java world, even inside the JDK itself.

Best

Durchholz, Joachim

unread,
Dec 19, 2012, 4:05:24 AM12/19/12
to jooq...@googlegroups.com
> I think developers tend to put too much effort on keeping things
> backward compatible and sometimes that's at the expense of
> quality at the end of the day. It is a hot debate in the java
> world, even inside the JDK itself.

It's essentially a lose-lose choice.

Without backwards compatibility, you'll end with disgruntled
programmers who hate every upgrade because it means so much work.
Only MS can get away with that.

With backwards compatibility, you're stuck with choices that start
to get hated because the world is changing and so are the
requirements.
Again, only MS can get away with that ;-)

The Linux people have found a very interesting tactics: They make
a clear distinction whether you're "inside" or "outside" (my
terminology).
"Inside" means inside the kernel. You're fully exposed to massive
changes in any available APIs. If that's too much work, your only
option is to GPL your code so they'll keep it running as the APIs
change. (You're still expected to fix bugs in your code, of
course.)
"Outside" means outside the kernel, i.e. userland. Userland APIs
are kept stable for decades if humanly possible.

Hm. Maybe that's the interesting point: Don't be
backwards-compatible for everything; that way lies madness.
Instead, give the application programmers the choice whether they
prefer a feature-complete but possibly maintenance-intensive API
or a feature-restricted but eternal one.
For Jooq, the easiest way would probably be adding annotations
on classes, members, and test cases - could be named @Eternal or
something.
Something annotated @Eternal would be there to stay, even in Jooq
42.0. Something without that annotation might get deprecated, or
have slight semantic changes.
Of course, it would be hard to determine what could be annotated
that way. It should be the kind of commitment that programmers
can bet serious money on.

Just tossing around ideas :-)

Lukas Eder

unread,
Dec 19, 2012, 11:54:48 AM12/19/12
to jooq...@googlegroups.com
As always, thanks guys, for sharing your thoughts! :-)

> It's essentially a lose-lose choice.

Well, people still win. They could've developed (and maintained)
something like jOOQ themselves, which would have been much more
expensive. The occasional bug / funny feature is usually acceptable
just as much as the occasional backwards-incompatibility of API or of
behaviour. I tend to see the glass half-full, when I get something for
free, as long as I'm made aware of these things through user groups,
release notes, etc.

> Again, only MS can get away with that ;-)

Actually, I find MS pretty impressive. You can probably still run
dinosaur Win95 programs on Windows 8. Try that with Apple's
products...
And there are others. Take PHP, for instance. The most impactful
backwards-compatibility that I have ever seen. Consider this piece of
code:

-----------------------------------------------
$joe = new Person();
$joe->sex = 'male';

$betty = $joe;
$betty->sex = 'female';

echo $joe->sex;
-----------------------------------------------
Output in PHP4: 'female' // $betty = $joe copies by value
Output in PHP5: 'male' // $betty = $joe copies by reference

Try to maintain any sensible data structure compatibly between PHP4
and 5... Still, they got away with it, somehow.

Other examples:
- HSQLDB 1.x -> 2.x (from proprietary to SQL standard)
- JDom 1.x -> 2.x
- JDBC x.x -> y.y (without Java 8's extension methods, API evolution
is hard in Java)
- Scala (lots of language experimentation there). Actually, with
implicit defs, I'm not sure if anything can be developed
backwards-compatibly in Scala
- jOOQ 2.x -> 3.x (e.g. some inevitable changes due to making typed
row value expressions first-class citizens)

> The Linux people have found a very interesting tactics: They make
> a clear distinction whether you're "inside" or "outside" (my
> terminology).

Yes, I try to do the same. You can never rely on jOOQ's internals.
That's why they're package-private within org.jooq.impl, or documented
in the Javadoc ("internal to jOOQ, do not use").

> For Jooq, the easiest way would probably be adding annotations
> on classes, members, and test cases - could be named @Eternal or
> something.
> Something annotated @Eternal would be there to stay, even in Jooq
> 42.0. Something without that annotation might get deprecated, or
> have slight semantic changes.

You wish :-)

1. It would take me forever to carefully assess the applicability of
this annotation for every class/member
2. I find @Internal a much more interesting and reliable information.
With @Internal, you can be sure that it's a bad idea to use this. (I
might actually do that! This is #2026:
https://github.com/jOOQ/jOOQ/issues/2026).
3. From my jOOQ experience, I've had so many bad and incomplete ideas
implemented and thrown out again, I wouldn't dare put the @Eternal
annotation anywhere.

> Of course, it would be hard to determine what could be annotated
> that way. It should be the kind of commitment that programmers
> can bet serious money on.

Well, if I get a cash advance on those bets, we can start discussing :-)

I think jOOQ should follow the semantic versioning rules explained in
http://semver.org, which was suggested by Vladislav Rastrusny on this
user group, here in early 2012:
https://groups.google.com/d/topic/jooq-user/3wyTXLwX9Sw/discussion

I have slightly adapted the rules of semver to my own use, as full
backwards-compatibility between minor releases in a DSL like jOOQ
cannot be achieved, as I need to frequently add methods to interfaces,
which aren't supposed to be implemented by client code anyway.

Probably, there should be a chapter in the manual: "Semantic
Versioning as understood by jOOQ": Let's register this as #2027:
https://github.com/jOOQ/jOOQ/issues/2027

Cheers
Lukas

Lukas Eder

unread,
Dec 21, 2012, 7:19:05 AM12/21/12
to jooq...@googlegroups.com
> For Jooq, the easiest way would probably be adding annotations
> on classes, members, and test cases - could be named @Eternal or
> something.
> Something annotated @Eternal would be there to stay, even in Jooq
> 42.0. Something without that annotation might get deprecated, or
> have slight semantic changes.

I've been investigating the possible applicability of such an @Eternal
(or as I prefer @Internal) annotation. On this user group, we had
discussed the potential usefulness of the current @Support annotation
as well, which indicates whether some method / type is supported in a
given SQL dialect.

I would like to evolve jOOQ in a way that annotation processing at a
compiler level is possible. These things are done in frameworks like
- Project Lombok (http://projectlombok.org)
- Checker Framework (http://types.cs.washington.edu/checker-framework)

The latter is a really interesting case, where things like nullability
are statically analysed by the compiler through annotation processing.
What I would like to see is this:
- jOOQ has @Internal and @Support annotations
- client code can activate such annotation processing for either javac
and/or Eclipse
- The compiler would then emit warnings that can be suppressed
specifically if needed

An interesting insight is given here, in this question (although the
warning is emitted at the callee-site, not the call-site):
http://stackoverflow.com/q/1752607/521799

Does anyone have any experience with javac's APT API? Is anyone
interested in providing a contribution in that field?

Cheers
Lukas

Stéphane Cl

unread,
Dec 26, 2012, 3:37:30 AM12/26/12
to jooq...@googlegroups.com
Hello Lukas,

Unfortunately I am in no position to help.
However, while It may have improved by now, I had to give up using lombok 2 or 3 years ago because it was breaking too many IDE features. The only option was to use "delombok" to actually generate the code behind annotation. If you are going this route, please do it in such a way that annotations can be expanded at generation time to make things transparent for IDEs.

Best

Lukas Eder

unread,
Dec 26, 2012, 6:29:39 AM12/26/12
to jooq...@googlegroups.com
Hi Stéphane,

> However, while It may have improved by now, I had to give up using lombok 2
> or 3 years ago because it was breaking too many IDE features. The only
> option was to use "delombok" to actually generate the code behind
> annotation. If you are going this route, please do it in such a way that
> annotations can be expanded at generation time to make things transparent
> for IDEs.

So far, I have only intended to add annotations that would emit
compiler warnings if a possibly wrong configuration was applied (e.g.
accessing internals, accessing unavailable features for the local SQL
dialect). In that sense, the added value is purely optional. As jOOQ
is a very "IDE-oriented" library, I think that code-generation from
annotations won't be on the roadmap very soon
Reply all
Reply to author
Forward
0 new messages