Generate Records with Java 8 Optionals for nullable fields

790 views
Skip to first unread message

jamesl...@gmail.com

unread,
Sep 29, 2015, 2:36:55 AM9/29/15
to jOOQ User Group
Is it currently possible to generate Record classes that return a java 8 Optional type for nullable fields?

Thanks,
James

Lukas Eder

unread,
Sep 29, 2015, 3:52:45 AM9/29/15
to jooq...@googlegroups.com
Hello,

Yes, you can implement a Converter for this and hook your Converter into the code generator:

It will be a bit of work as there is no way to match all nullable columns in the code generator configuration - you'll have to match them all by name. Currently, we do not have any out-of-the-box support for this, just as we do not have Option support in the jOOQ Scala integration. One of the main reasons is the fact that the Option(al) type is rather difficult to enforce in the context of:

- outer joins
- functions
- grouping sets
- unions
- etc.

Hope this helps,
Lukas

--
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 jooq-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

jamesl...@gmail.com

unread,
Sep 29, 2015, 11:28:40 AM9/29/15
to jOOQ User Group
Thanks Lukas.
If I added a custom convertor, would that just impact the `Record` setters and getters or would that also update the fields in the TableImpls? If it did the later as well I could see where that might make even selects more difficult.

Could you give me a simple example of where it makes it more difficult?

Lukas Eder

unread,
Sep 30, 2015, 11:38:22 AM9/30/15
to jooq...@googlegroups.com
2015-09-29 17:28 GMT+02:00 <jamesl...@gmail.com>:
Thanks Lukas.
If I added a custom convertor, would that just impact the `Record` setters and getters or would that also update the fields in the TableImpls?

Every type reference will be updated, including TableImpls, POJOs, etc.
 
If it did the later as well I could see where that might make even selects more difficult.

Yes, indeed. 

Could you give me a simple example of where it makes it more difficult?

If your column is:

TableField<MyTable, Optional<String>> TEXT;

Then, you won't be able to call built-in functions like DSL.substring(Field<String>, int), because the types don't match. It's a relatively high price to pay for little additional value.

Another example, consider the column

TableField<MyTable, Integer> ID;

Obviously, an ID column is hardly ever nullable, thus you'll model that with Integer (as opposed to Optional<Integer>)

Now, you create a LEFT JOIN like this:

Result<?> result = 
    select()
    .from(MY_OTHER_TABLE)
    .leftOuterJoin(MY_TABLE).on(...)
    .fetch();

What does the following yield?

result.get(0).getValue(MY_TABLE.ID)

You would get an Integer value, even if you should be getting an Optional<Integer> value, because after a LEFT JOIN, you might get NULL values even for NOT NULL columns.

There's no workaround for the latter. SQL has NULL. Java has null. The two special values are just the best match for each other (even if they're not exactly the same). Optional seems like a good idea at first, but it is not, when you work with SQL.

I hope this helps,
Lukas

jamesl...@gmail.com

unread,
Sep 30, 2015, 12:01:07 PM9/30/15
to jOOQ User Group
Thanks Lukas. This really helps to understand all the ramifications.
I would say we currently have a rather simple data structure. I took a stab at implementing a Convertor yesterday and got pretty close adding it for a specific field like you suggested in your first reply. My one problem was that I was unable to really do what I wanted for the `toType` method.
For example I wanted it to look like:

@Override
public Class<Optional<String>> toType() {
   
return Optional<String>.class;
}

Obviously the above won't compile but if you have any suggestions for a workaround I'd love to hear them.

Thanks again for your help.
James

Lukas Eder

unread,
Sep 30, 2015, 12:02:44 PM9/30/15
to jooq...@googlegroups.com
Unfortunately, you cannot create that type, unless you "cheat":

@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Class<Optional<String>> toType() {

    
return (Class) Optional.class;
Reply all
Reply to author
Forward
0 new messages