Case-sensitive Pojo code generation getters and setters

728 views
Skip to first unread message

elect...@gmail.com

unread,
Dec 23, 2013, 10:08:23 AM12/23/13
to jooq...@googlegroups.com
Hello,

I have a table with a column named "passwordEncrypted" (case sensitive and camel cased).

I'd like Jooq to generate the Pojo with :

- setPasswordEncrypted()
- getPasswordEncrypted()

instead of

- setPasswordencrypted()
- getPasswordencrypted()

Do I have to specify my own GeneratorStrategy ( http://www.jooq.org/doc/3.1/manual/code-generation/codegen-advanced/ ) or is there a built-in option for that?

Thanks in advance!


Lukas Eder

unread,
Dec 24, 2013, 3:19:07 AM12/24/13
to jooq...@googlegroups.com
Hello,

With jOOQ 3.1, you will indeed have to write your own GeneratorStrategy. You might have to debug through the code generation process to see how to best implement the single column-renaming.

With jOOQ 3.2, there is now a new XML-based matcher strategy, which allows you to perform such a simple renaming through the use of regular expression pattern matching. This is documented here:

For example

      <fields>
      
        <!-- The field matcher regular expression. -->
        <expression>passwordEncrypted</expression>
        
        <fieldSetter><expression>setPasswordEncrypted</expression></fieldSetter>
        <fieldGetter><expression>getPasswordEncrypted</expression></fieldGetter>
      </fields>


2013/12/23 <elect...@gmail.com>

--
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/groups/opt_out.

elect...@gmail.com

unread,
Dec 24, 2013, 11:03:42 AM12/24/13
to jooq...@googlegroups.com
Ok thanks, so I'm trying the following (in Maven's POM) :

http://pastebin.com/dC1WPkVU

But get this error :

----------------------------
[ERROR] Failed to execute goal org.jooq:jooq-codegen-maven:3.2.2:generate (default) on project XXXXX: Unable to parse configuration of mojo org.jooq:jooq-codegen-maven:3.2.2:generate for parameter expression: Cannot configure instance of org.jooq.util.jaxb.Matchers$Fields from passwordEncrypted -> [Help 1]
----------------------------

Is there something wrong with my matchers configuration?


Lukas Eder

unread,
Dec 26, 2013, 4:23:22 AM12/26/13
to jooq...@googlegroups.com
Hmm, I see, this error seems to appear only when running jOOQ's code generator with Maven.
Apparently, Maven cannot map XML configurations to nested classes, even if they're correctly JAXB-annotated. I've registered #2910 for this:

Thank you for reporting. This issue should be fixed as soon as possible, and merged to jOOQ 3.2.3.

In the mean time, I suspect you will have to resort to any of these workarounds:
- Use jOOQ codegen in the "standalone" mode, instead of the Maven plugin
- Write your own Maven plugin to work around this issue


2013/12/24 <elect...@gmail.com>

elect...@gmail.com

unread,
Dec 26, 2013, 5:06:57 AM12/26/13
to jooq...@googlegroups.com
Thanks Lukas!

Lukas Eder

unread,
Dec 30, 2013, 6:01:17 AM12/30/13
to jooq...@googlegroups.com, elect...@gmail.com
I've tried to reproduce this with an alternative XSD, which generates only top-level JAXB types. The same problem appears. So there has to be some other reason...
Have you tried to track this down any further, in the mean time?


2013/12/26 <elect...@gmail.com>
Thanks Lukas!

elect...@gmail.com

unread,
Dec 30, 2013, 7:19:49 AM12/30/13
to jooq...@googlegroups.com, elect...@gmail.com
Hello Lukas,

I don't work as much as I'd like on my project right now, but what I decided to do is to use my own Maven plugin and call GenerationTool.main(configuration) by myself. It is still untested yet, but I don't see why it wouldn't work.

I didn't try to find why jooq-codegen-maven isn't working properly though, sorry.

Lukas Eder

unread,
Dec 30, 2013, 8:02:03 AM12/30/13
to jooq...@googlegroups.com



2013/12/30 <elect...@gmail.com>

Hello Lukas,

I don't work as much as I'd like on my project right now, but what I decided to do is to use my own Maven plugin and call GenerationTool.main(configuration) by myself. It is still untested yet, but I don't see why it wouldn't work.

I didn't try to find why jooq-codegen-maven isn't working properly though, sorry.

OK, no worries. I'll figure it out.

Cheers
Lukas

Lukas Eder

unread,
Dec 31, 2013, 6:02:15 AM12/31/13
to jooq...@googlegroups.com
... Unfortunately, it looks like we've fallen into an impedance mismatch trap between XSD, JAXB, XJC and Maven. Maven's understanding of XML is much simpler than XSD's / JAXB's, which is why it couldn't read this particular configuration. The way I see this, this can only be solved by incompatibly changing the XSD for the matcher strategy to be configured as such:

  <strategy>
      <matchers>
          <fields>
              <field>
                  <expression>DUMMY</expression>
                  <fieldSetter><expression>DUMMY</expression></fieldSetter>
                  <fieldGetter><expression>DUMMY</expression></fieldGetter>
              </field>
          </fields>
      </matchers>
  </strategy>

Notice the additional <fields><field/></fields> indirection. This fix has been implemented for the upcoming jOOQ 3.3.0 and won't be merged to jOOQ 3.2 because of the incompatibility of XSD changes. There will be a remark in the jOOQ 3.2 manual indicating that the matcher strategy cannot be used with the maven plugin.


2013/12/30 Lukas Eder <lukas...@gmail.com>

elect...@gmail.com

unread,
Dec 31, 2013, 3:07:14 PM12/31/13
to jooq...@googlegroups.com
Lukas,

So finally I use my own Maven plugin and it works well.

But for the camel cased setters and getters, it seems the only format that I'm not able to generate is the one I want!!

I try to apply the format to all fields, using : fields.setExpression("^(.+)$");

For "passwordEncrypted", I want the generated getter to be "getPasswordEncrypted()".

This doesn't work because the first letter is not uppercased :

matcherRuleGetter.setExpression("get$1");
matcherRuleGetter.setTransform(MatcherTransformType.AS_IS);

Results in "getpasswordEncrypted()".

I also tried :

matcherRuleGetter.setExpression("get_$1");
matcherRuleGetter.setTransform(MatcherTransformType.CAMEL);

Results in "getPasswordencrypted()".

And :

matcherRuleGetter.setExpression("get_$1");
matcherRuleGetter.setTransform(MatcherTransformType.PASCAL);

Results in "GetPasswordencrypted()".

Sadly I think (not sure) that it's not possible to specify, in a Java's regular expressions replacement string, that we want to convert a character to uppercase.

I hope the format I'm looking for is possible to generate since, in my opinion, it's the one that makes the more sense when dealing with pojos, don't you think? It would follow the beans' getters and setters specification.


elect...@gmail.com

unread,
Jan 1, 2014, 11:18:54 AM1/1/14
to jooq...@googlegroups.com
I'll simply use a custom GeneratorStrategy, it's not that bad! :-)

Lukas Eder

unread,
Jan 2, 2014, 6:58:31 AM1/2/14
to jooq...@googlegroups.com
Hi there,

2013/12/31 <elect...@gmail.com>

Lukas,

So finally I use my own Maven plugin and it works well.

But for the camel cased setters and getters, it seems the only format that I'm not able to generate is the one I want!!

I try to apply the format to all fields, using : fields.setExpression("^(.+)$");

For "passwordEncrypted", I want the generated getter to be "getPasswordEncrypted()".

This doesn't work because the first letter is not uppercased :

matcherRuleGetter.setExpression("get$1");
matcherRuleGetter.setTransform(MatcherTransformType.AS_IS);

Results in "getpasswordEncrypted()".

I also tried :

matcherRuleGetter.setExpression("get_$1");
matcherRuleGetter.setTransform(MatcherTransformType.CAMEL);

Results in "getPasswordencrypted()".

And :

matcherRuleGetter.setExpression("get_$1");
matcherRuleGetter.setTransform(MatcherTransformType.PASCAL);

Results in "GetPasswordencrypted()".

Thanks for the detailed listing. Yes, you're right, none of the transform types will work for your use-case, as MatcherTransformType is applied only after regex replacement.
 
Sadly I think (not sure) that it's not possible to specify, in a Java's regular expressions replacement string, that we want to convert a character to uppercase.

I don't think you can do this, either. This is nicely explained in this Stack Overflow question here:
 
I hope the format I'm looking for is possible to generate since, in my opinion, it's the one that makes the more sense when dealing with pojos, don't you think? It would follow the beans' getters and setters specification.

Yes it would make more sense. I guess, this could be resolved with an additional MatcherTransformType? We would need one that is similar to CAMEL / PASCAL casing (removing underscores, uppercasing subsequent letters) but would keep casing within words AS_IS.

What would be an appropriate name for such a transformation scheme?

I have registered #2924 for this. Should be easy to fix:

I'll simply use a custom GeneratorStrategy, it's not that bad! :-)

OK :-)

electrotype

unread,
Jan 2, 2014, 11:17:54 AM1/2/14
to jooq...@googlegroups.com
Any name will be good for me! Thanks Lukas.
--
You received this message because you are subscribed to a topic in the Google Groups "jOOQ User Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jooq-user/1iy0EdWe_T8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jooq-user+...@googlegroups.com.

elect...@gmail.com

unread,
Jan 5, 2014, 4:56:32 PM1/5/14
to jooq...@googlegroups.com
Lukas, I found another problem.

Because I use a custom Generator strategy, which generates setPasswordEncrypted() for the field passwordEncrypted on my User entity pojo, the mapping doesn't work anymore.

I get the User entity using its DAO : userDao.fetchOne(user.username, "toto");

The record is found. But when Jooq tried to map it to the pojo, using mapper().map(record), the setPasswordEncrypted() setter is not found so the field stays NULL. Why? Because of the Utils#getMatchingSetters() method, which calls StringUtils#toCamelCase(name). But :

StringUtils.toCamelCase("passwordEncrypted") returns "Passwordencrypted" so setPasswordencrypted() is searched, but not setPasswordEncrypted()!

In Utils#getMatchingSetters(), maybe you could look for true camel cased versions too?

Thanks!

Lukas Eder

unread,
Jan 6, 2014, 4:25:17 AM1/6/14
to jooq...@googlegroups.com
Nice catch!

The DefaultRecordMapper implements the same naming assumptions as previously described:

This will have to be fixed in jOOQ 3.3 as well:

In the mean time, you will probably have to resort to writing your own RecordMapperProvider to override this behaviour:

Cheers
Lukas




2014/1/5 <elect...@gmail.com>

--
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.

elect...@gmail.com

unread,
Jan 12, 2014, 1:47:51 PM1/12/14
to jooq...@googlegroups.com

> In the mean time, you will probably have to resort to writing your own RecordMapperProvider to override this behaviour:
> http://www.jooq.org/doc/3.2/manual/sql-execution/fetching/pojos-with-recordmapper-provider/

There are too many private/package private/final elements to easily override the behaviour. For example, extending DefaultRecordMapper doesn't allow to override the map() method. Also, the inner class MutablePOJOMapper is private so I can't use it. I would have to copy/paste almost all the code to change the behavior and I don't want to do that.

My temporary workaround will be to use only lowercase names for all columns in the database!

Lukas Eder

unread,
Jan 13, 2014, 5:49:21 AM1/13/14
to jooq...@googlegroups.com
Hello,

2014/1/12 <elect...@gmail.com>


> In the mean time, you will probably have to resort to writing your own RecordMapperProvider to override this behaviour:
> http://www.jooq.org/doc/3.2/manual/sql-execution/fetching/pojos-with-recordmapper-provider/

There are too many private/package private/final elements to easily override the behaviour. For example, extending DefaultRecordMapper doesn't allow to override the map() method. Also, the inner class MutablePOJOMapper is private so I can't use it. I would have to copy/paste almost all the code to change the behavior and I don't want to do that.

Yes, all these private / final elements are intentional. Even if you would access or extend an accessible MutablePOJOMapper, chances are high that you would run into incompatible changes between minor releases. If you wanted to fix this right now, you would really need to patch the original sources.
 
My temporary workaround will be to use only lowercase names for all columns in the database!

That'll work as well, of course.

Regards,
Lukas 
Reply all
Reply to author
Forward
0 new messages