Quick blog -- as always, the last 20% usually takes up 80% of the time.
This time, it was trying to simply convert Camel Case into equivalent underscore Enum values.
Ok, not that 'simply', but still -- I'm using Hibernate Tools to reverse engineer from JDBC some JPA entities, and that part is working fine. Now, UI and some processes prefer to use a Model that is on top of the entity/dto. So, I thought I would be nice and auto-generate the Model's that some other programmers swear by to make their job easier.
Hibernate Tools just went to FreeMarker, which I was excited for, and I wrote most of the .ftl up for my Model. Until I hit Camel Case.
You see, what they are trying to do is create an ENUM version of each field; I'm not going into detail why, but simply that code-generation wise --
fieldOne -> FIELD_ONE
myReallyLongComboField -> MY_REALLY_LONG_COMBO_FIELD
After a lot of messing around in Freemarker and regular expressions, finally got the solution in two lines in the .ftl file (very important the < /#macro> is where it is now):
<#macro toUnderScore camelCase>
${camelCase?replace("[A-Z]", "_$0", 'r')?upper_case}< /#macro>
Then, make calls like:
<@toUnderScore camelCase=property.name/>
Perfect!
I've had quite a bit of experience in the past with Velocity, and put in some work in code-gen tools like Middlegen (now defunct). Once you have a process/template for commonly used code pieces, code generation really helps enforce consistency and good practice.
Subscribe to:
Post Comments (Atom)
5 comments:
Hi... Just got here and I found your macro very useful... but...
Do you have the reverse one? I'm not good at regexps, and I need to convert from underscore to camelCase in FreeMarker...
Might have solved your problem but it's no good as a general converter from camelCase to underscores.
Example strings to undermine my claim? Try:
- XMLParserProperty
- PropertyWithCapFirstCharacter
Sorry, shouldn't have stopped here...The general solution would be
yourWhateverString.replaceAll("(?<=[a-z0-9])[A-Z]|(?<=[a-zA-Z])[0-9]|(?<=[A-Z])[A-Z](?=[a-z])", "_$0")
Below is the documentation straight out of RegexBuddy (hope Blogger doesn't garble it):
// (?<=[a-z0-9])[A-Z]|(?<=[a-zA-Z])[0-9]|(?<=[A-Z])[A-Z](?=[a-z])
//
// Match either the regular expression below (attempting the next alternative only if this one fails) «(?<=[a-z0-9])[A-Z]»
// Assert that the regex below can be matched, with the match ending at this position (positive lookbehind) «(?<=[a-z0-9])»
// Match a single character present in the list below «[a-z0-9]»
// A character in the range between "a" and "z" «a-z»
// A character in the range between "0" and "9" «0-9»
// Match a single character in the range between "A" and "Z" «[A-Z]»
// Or match regular expression number 2 below (attempting the next alternative only if this one fails) «(?<=[a-zA-Z])[0-9]»
// Assert that the regex below can be matched, with the match ending at this position (positive lookbehind) «(?<=[a-zA-Z])»
// Match a single character present in the list below «[a-zA-Z]»
// A character in the range between "a" and "z" «a-z»
// A character in the range between "A" and "Z" «A-Z»
// Match a single character in the range between "0" and "9" «[0-9]»
// Or match regular expression number 3 below (the entire match attempt fails if this one fails to match) «(?<=[A-Z])[A-Z](?=[a-z])»
// Assert that the regex below can be matched, with the match ending at this position (positive lookbehind) «(?<=[A-Z])»
// Match a single character in the range between "A" and "Z" «[A-Z]»
Thanks. This is very useful. The one place where it falls down is if you have terms that are in all caps, like "PDF". This regex inserts a space between each letter. Any ideas how to modify to account for that?
Thank you Works like a charm
HelloWorld -> _HELLO_WORLD
if you want HELLO_WORLD without the first _
add "substring(1)"
like ${camelCase?replace("[A-Z]", "_$0", 'r')?upper_case?substring(1)}
Post a Comment