Code generation: is there a way to rename PK getter in POJOs

27 views
Skip to first unread message

Christian Meyer

unread,
Jun 17, 2016, 2:40:15 PM6/17/16
to jOOQ User Group
Hi,

I'm trying hard to find a way to have a common getter method in generated POJOs, e.g. getPrimaryKey().
The problem so far is that some tables may have a composite PK, some just have something like ID.
My plan is to have a marker interface containing getPrimaryKey(). Each POJO implements that interface.

Is there a way to archive that?

Thanks,
Christian

Lukas Eder

unread,
Jun 19, 2016, 2:01:45 PM6/19/16
to jooq...@googlegroups.com
Hello Christian,

Yes, this should be possible. I suspect your marker interface should be generic with the primary key type:

public interface PKHolder<PKType> {
    PKType getPrimaryKey();
}

Now, use a generator strategy to add the interface to the "implements" section of each relevant POJO:

There is also the possibility to add a configurative generator strategy, but that won't be sufficient in your use-case as you probably need to introspect the primary key type:

Now the last step is to actually implement the marker interface and the getPrimaryKey() method. This can be done by generating a custom code section:

I think with the above pointers, it should be possible to achieve what you want to do. Please, let me know if you encounter any issues or if some detail is unclear.

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.

Christian Meyer

unread,
Jun 20, 2016, 4:45:07 AM6/20/16
to jOOQ User Group
Hello Lukas,


Am Sonntag, 19. Juni 2016 20:01:45 UTC+2 schrieb Lukas Eder:
Hello Christian,

Yes, this should be possible. I suspect your marker interface should be generic with the primary key type:

public interface PKHolder<PKType> {
    PKType getPrimaryKey();
}

That's right!
 

Now, use a generator strategy to add the interface to the "implements" section of each relevant POJO:

I got that already :-)
 
There is also the possibility to add a configurative generator strategy, but that won't be sufficient in your use-case as you probably need to introspect the primary key type:

That's right.
 
Now the last step is to actually implement the marker interface and the getPrimaryKey() method. This can be done by generating a custom code section:

OK, I see, I was at that point already but I wasn't sure.

I think with the above pointers, it should be possible to achieve what you want to do. Please, let me know if you encounter any issues or if some detail is unclear.

I will, thanks!

ciao
Christian

Christian Meyer

unread,
Jun 20, 2016, 8:04:02 AM6/20/16
to jOOQ User Group
Hi Lukas,

looks like I need some help from you.
Currently, I have an interface which looks like this:

public interface IdentifiableDomain<PK extends Serializable> {
    PK getPrimaryKey
();
}

Now I also have a generator class:

public class DomainGenerator extends JavaGenerator {

   
@Override
   
protected void generatePojoClassFooter(TableDefinition table, JavaWriter out) {
       
UniqueKeyDefinition primaryKey = table.getPrimaryKey();
   
}

}

And now, I don't know how to get any further. How can I get the specific primary key type from UniqueKeyDefinition?

Thanks a lot...

ciao
Christian

Lukas Eder

unread,
Jun 21, 2016, 7:53:21 AM6/21/16
to jooq...@googlegroups.com
Hello Christian,

There are two steps to follow.
First, you have to introspect the primaryKey's columns via UniqueKeyDefinition.getKeyColumns()
Then, you have to find out the applicable Java type via ColumnDefinition.getType().getJavaType(). There you should have everything you need. Perhaps, some debugging through the code generator might also help to find out what API elements will return the most appropriate information. You could even make use of JavaGenerator's internals in order to generate imports for such types.

I'm not sure how you intend to model composite primary keys. It could be done e.g. with a jOOλ Tuple[N] type (see https://github.com/jOOQ/jOOL)

I hope this helps. Let me know if you have any specific questions about the above.
Lukas

Christian Meyer

unread,
Jun 21, 2016, 11:02:12 AM6/21/16
to jOOQ User Group
Hi Lukas,

thanks for your patience...

Am Dienstag, 21. Juni 2016 13:53:21 UTC+2 schrieb Lukas Eder:
Hello Christian,

There are two steps to follow.
First, you have to introspect the primaryKey's columns via UniqueKeyDefinition.getKeyColumns()
Then, you have to find out the applicable Java type via ColumnDefinition.getType().getJavaType(). There you should have everything you need. Perhaps, some debugging through the code generator might also help to find out what API elements will return the most appropriate information. You could even make use of JavaGenerator's internals in order to generate imports for such types.

Aha, I will look into that, thanks a lot.
 
I'm not sure how you intend to model composite primary keys. It could be done e.g. with a jOOλ Tuple[N] type (see https://github.com/jOOQ/jOOL)

Yep, that's the problem. First, I thought about solving it the JPA-way. But then again, this is not doable: Having a(n embedded) FooBarPk doesn't help when you want to do something like:

dslContext.selectFrom(rTable).where(pkField.eq(source.primaryKey))

where
  • rTable is of type Table<R> (R extends UpdatableRecord<R>)
  • pkField is of type Field<PK> (PK extends Serializable)
  • source is of type IdentifiablePojo<PK>
From a quick look at jOOλ I don't know how it can be used here...

Actually, in DAOImpl you use getId() which is generated via your generator. I guess it also works for composite primary keys, right? Is it possible to use this implementation also to implement getPrimaryKey()?

Thanks and regards
Christian

Lukas Eder

unread,
Jun 21, 2016, 6:12:41 PM6/21/16
to jooq...@googlegroups.com
2016-06-21 16:02 GMT+01:00 Christian Meyer <christi...@gmail.com>:
Hi Lukas,

thanks for your patience...

No worries :)
 
I'm not sure how you intend to model composite primary keys. It could be done e.g. with a jOOλ Tuple[N] type (see https://github.com/jOOQ/jOOL)

Yep, that's the problem. First, I thought about solving it the JPA-way. But then again, this is not doable: Having a(n embedded) FooBarPk doesn't help when you want to do something like:

dslContext.selectFrom(rTable).where(pkField.eq(source.primaryKey))


Aha, so you could use jOOQ's Row[N] types or Record[N] types instead! Because with those, you can write stuff like:

dslContext.selectFrom(rTable).where(pkRow.eq(source.primaryKey))

See for instance

Actually, in DAOImpl you use getId() which is generated via your generator. I guess it also works for composite primary keys, right? Is it possible to use this implementation also to implement getPrimaryKey()?

Yes, indeed. I hadn't thought of that. In these cases, DAO's <T> type (primary key type) gets bound to something like Record2<Integer, String>. It's a bit of work, but certainly you will find good hints in the DAO generation logic inside of JavaGenerator

Lukas

Christian Meyer

unread,
Jun 22, 2016, 8:47:06 AM6/22/16
to jOOQ User Group
OK, Lukas, I will come back to you later. Thanks for your input!

Christian Meyer

unread,
Jun 22, 2016, 12:25:12 PM6/22/16
to jOOQ User Group
Hi Lukas,

one quick question. Something I saw in your DAOImpl class: you cast a T to a Record (private equal method).

return row(pk).equal((Record) id);

Is this really safe and why? Maybe there's something I don't understand.

There are more questions on the way ;-)

Cheers,
Christian

Lukas Eder

unread,
Jun 25, 2016, 8:24:18 AM6/25/16
to jooq...@googlegroups.com
2016-06-22 18:25 GMT+02:00 Christian Meyer <christi...@gmail.com>:
Hi Lukas,

one quick question. Something I saw in your DAOImpl class: you cast a T to a Record (private equal method).

return row(pk).equal((Record) id);

Is this really safe and why? Maybe there's something I don't understand.

It's safe because the implicit contract on the type <T> is for:

- Single column primary keys to be of the type T of the column
- Composite primary keys to be of the type Record[N]<T1, T2, ..., T[N]>

It's a contract, but it cannot be easily expressed in code. The code generator will adhere to this contract. Custom DAO implementations might not, but as many other jOOQ APIs, DAO is not meant for random implementation by users, so it's... "safe" :)

Hope this helps,
Lukas

Christian Meyer

unread,
Jun 27, 2016, 7:55:38 AM6/27/16
to jOOQ User Group
Hi Lukas,


Am Samstag, 25. Juni 2016 14:24:18 UTC+2 schrieb Lukas Eder:
 
It's safe because the implicit contract on the type <T> is for:

- Single column primary keys to be of the type T of the column
- Composite primary keys to be of the type Record[N]<T1, T2, ..., T[N]>

It's a contract, but it cannot be easily expressed in code. The code generator will adhere to this contract. Custom DAO implementations might not, but as many other jOOQ APIs, DAO is not meant for random implementation by users, so it's... "safe" :)
 
Aha, I begin to understand how it is solved and I will start looking more closely at the code generator now.

Thanks again,
Christian
Reply all
Reply to author
Forward
0 new messages