This part of the tutorial is about basic Java code generation using CodeModel.
My current job is all about ETL – i.e. I have to transform flat formatted data to xml and back again… exciting, uh?
Anyway, my first step was to write classes to reflect the different type of “records” that could be part of the flat file, but the “specification” for the structure keep changing (sounds familiar ?). Being absolutely lazy I realized that I needed something to generate that code for me!
Surely there are many other frameworks I am not aware of, maybe even better, but I found out CodeModel and decided to give it a try, also because it is used (beyond the scene) by JAXB – the library I am using to do xml-related stuff.
As for other stuff from glassfish site, I think its pretty good, but the documentation could have been more developer-friendly.
So, I write down this little tutorial for other people that want to use this nice library.
For this guide I will use codemodel-2.4.jar, that could be downloaded from here http://download.java.net/maven/2/com/sun/codemodel/codemodel/2.4/.
The very first steps are:
1) instantiate the root of the code DOM;
2) use it to create the class;
This is done in a couple of lines:
JCodeModel codeModel = new JCodeModel(); JDefinedClass definedClass = codeModel._class("ClassName");
Keep note that the name of the defined class should be the fully qualified name (i.e. with the package declaration).
The actual “java” file will be written calling the method
JCodeModel.build(File destDir);
The bare minimum code needed to generate an (absolutely empty) “java” file looks like this:
JCodeModel codeModel = new JCodeModel(); try { JDefinedClass definedClass = codeModel._class("net.cardosi.MyNewClass"); codeModel.build(new File(".")); } catch (JClassAlreadyExistsException e) { // ... } catch (IOException e) { // ... }
and here’s the generated file that you will found in the net/cardosi/ folder:
package net.cardosi; public class MyNewClass { }
Surely we would like to add some field to this class, and here’s the needed method provided by JDefinedClass:
JDefinedClass.field(int mods, Class type, String name)
The first parameter define the accessor modificator (Public, Private, etc.), the second one is to tell the Class of the variable to be generated, and the third one is for the field name.
Let’s add an int called “intVar” to our class:
JCodeModel codeModel = new JCodeModel(); try { JDefinedClass definedClass = codeModel._class("net.cardosi.MyNewClass"); codeModel.build(new File(".")); JFieldVar field = definedClass.field(JMod.PRIVATE, int.class, "intVar"); } catch (JClassAlreadyExistsException e) { // ... } catch (IOException e) { // ... }
and let’s see the result:
package net.cardosi; public class MyNewClass { private int intVar; }
of course it is possible to initialize the field with a “default” value:
JFieldVar.init(JExpression init);
and it is possible to create getter and setter for it
// Create the getter method and return the JFieldVar previously defined JMethod getterMethod = definedClass.method(int mods, Class type, String name); JBlock block = getterMethod.body(); block._return(field); // Create the setter method and set the JFieldVar previously defined with the given parameter JMethod setterMethod = definedClass.method(int mods, Class type, String name); setterMethod.param(int.class, "intParam"); setterMethod.body().assign(JExpr._this().ref("intVar"), JExpr.ref("intParam"));
While I found most the code-related stuff we have seen until now pretty intuitive to understand (JDefinedClass, JFieldVar, JMethod and JBlock), I do not mind to tell you I had my problems with JExpression and JExpr, and surely we will give them more attention.
But now let’s review the code we have written until now
JCodeModel codeModel = new JCodeModel(); try { String className = "net.cardosi.MyNewClass"; JDefinedClass definedClass = codeModel._class(className); String fieldName = "intVar"; String fieldNameWithFirstLetterToUpperCase = "IntVar"; JFieldVar field = definedClass.field(JMod.PRIVATE, int.class, fieldName); String getterMethodName = "get" + fieldNameWithFirstLetterToUpperCase; JMethod getterMethod = definedClass.method(JMod.PUBLIC, int.class, getterMethodName); JBlock block = getterMethod.body(); block._return(field); String setterMethodName = "set" + fieldNameWithFirstLetterToUpperCase; JMethod setterMethod = definedClass.method(JMod.PUBLIC, Void.TYPE, setterMethodName); String setterParameter = "intVarParam"; setterMethod.param(int.class, setterParameter); setterMethod.body().assign(JExpr._this().ref(fieldName), JExpr.ref(setterParameter)); codeModel.build(new File(".")); } catch (JClassAlreadyExistsException e) { // ... } catch (IOException e) { // ... }
And here’s the generated class
package net.cardosi; public class MyNewClass { private int intVar; public int getIntVar() { return intVar; } public void setIntVar(int intVarParam) { this.intVar = intVarParam; } }
Don’t miss the next part about Javadoc!
Very nice article, thanks for it! Only one small mistake in last paragraph. The method setIntVar shoud be void, not int.
LikeLike
Thanks for your correction. I’ve replaced
public int setIntVar(int intVarParam)
; withpublic void setIntVar(int intVarParam)
.LikeLike
Thanks a lot , very useful and simple tutorial.
LikeLike
A small correction:
in the code to initialize the setterMethod, it should return void not int.
it should be:
JMethod setterMethod = definedClass.method(JMod.PUBLIC,void.class,setterMethodName);
not
JMethod setterMethod = definedClass.method(JMod.PUBLIC,int.class,setterMethodName);
LikeLike
Thanks for your remark. I’ve replaced
JMethod setterMethod = definedClass.method(JMod.PUBLIC,void.class,setterMethodName);
withJMethod setterMethod = definedClass.method(JMod.PUBLIC,Void.TYPE,setterMethodName);
(that’s working in my “test” project”).LikeLike
Hi, thanks for sharing. I’m wondering if it’s OK to copy some of the text in my site?
LikeLike
That’s fine for me; I would be glad if you could add a link to this blog, though. You know, SEO stuff…. 🙂
LikeLike
Hi, nice article. I really like it!
LikeLike
Thanks 🙂
LikeLike
Hi, thanks for sharing. I’m wondering if it’s OK to copy some of the text in my site?
LikeLike
Yes, sure. I would just ask if you could add a link to my blog, too. Best.
Gab
LikeLike
Thanks for this article. It’s a good quick start material.
LikeLike
You welcome 🙂
LikeLike
Hello gabriolo. I have some question about using static defined field of class;
How I can use this field?
LikeLike