Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jOOQ select into POJO with mappings specified only for some fields

Tags:

I'm using jOOQ with plain SQL (not generated code). I'm trying to select directly into a POJO that has some fields of type enum.

MyType pojo = context.select().from(table("Table"))
            .where(field("ID").equal("1")).fetchOne()
            .into(MyType.class);

It seems to me that I can only specify a high-level mapper for my whole POJO, like so:

MyType pojo = context.select().from(table("Table"))
            .where(field("ID").equal("1")).fetchOne()
            .map(new RecordMapper<Record, MyType>() {
                @Override
                public MyType map(Record record) {
                    ...
                }
            });

I can't find a way to only provide mappings or converters for some of the fields. Specifically, I would like to tell jooq something like "convert all fields normally, except if the field in my POJO is of type MyEnum, in which case use this mapping (or converter)".

How can I specify mappers for some fields and not others?

BTW, I noticed I can do something similar at the configuration level, matching database field names with wildcards (as described here), but I think it would be better if the decision would be driven by the type of the fields in the POJO.

like image 999
Robert Mikes Avatar asked Jan 11 '17 20:01

Robert Mikes


1 Answers

There are different ways to tackle this problem:

1. Use the code generator

Obviously. I know you're not using it, but maybe someone who finds this question will be. In that case, the code generator will either:

  1. Generate enum types for you automatically (if you're using MySQL or PostgreSQL enums)
  2. Allow you to use <forcedTypes/>, where you can implement your own converters and/or bindings

2. Use an explicit converter / binding also with plain SQL

Even if you're not using the code generator, you can profit from custom converters / bindings by specifying your own DataType:

// Assuming that the enum type enumerates varchar values:
SQLDataType<MyEnum> myEnumType = 
    SQLDataType.VARCHAR.asConvertedDataType(new MyEnumConverter());

Now, you can use that type in plain SQL Field expressions, using DSL.field(String, DataType)

context.select(field("Column", myEnumType), ...)
       .from(table("Table"))

In this case, there will be no need for explicit conversion anymore in your record mapper, as the jOOQ Record will already contain the desired data type.

3. Use a custom RecordMapperProvider

If you're using any of the into(Class) methods, by default, the DefaultRecordMapper is used. It knows how to convert strings to enums by calling EnumClass.valueOf(stringValue). If that's not the desired behaviour (as your question suggests), then you can still override the default behaviour by providing your own RecordMapperProvider.

This is also a "high level mapper" as you called it, but you can register it globally and reuse it any time you want to map into MyType.class.

(4. using a converter registry)

A future version of jOOQ (not jOOQ 3.9 yet) may support a converter registry that allows for implementing default conversions for any pair of types <T, U>. This is issue #5713.

like image 96
Lukas Eder Avatar answered Sep 23 '22 10:09

Lukas Eder