Skip to content
Philip Helger edited this page Dec 21, 2020 · 5 revisions

This page contains code snippets and the created outcome, mainly based on the test cases available.

Prerequisites

  1. The most relevant object is JCodeModel - it contains all the data structures files etc for a single generation run. So final JCodeModel cm = new JCodeModel (); is always a good starting point.
  2. Afterwards you can create classes, interfaces and enumerations but you can also add resource files (like XML or SQL files) as part of your generated code. The example code snippet (see below for more) cm._package ("org.example")._class ("MyFirstClass"); would create the directory structure org/example and create a file MyFirstClass.java in that new directory.
  3. Once all of the code is generated, you need to serialize it to disk. The relevant class to do this is JCMWriter. It takes an instance of JCodeModel as a constructor argument, lets you customize the output a bit and via the build method the results are written to a directory on disk (via the File-based methods) or onto a generic Writer of your choice. Different base directory for Java-classes and resources can be provided to accomodate e.g. the requirements of the Maven folder structure.

Need to knows

  • You can create invalid Java code - there is no syntax or consistency checker build-in

My first class

Create a class with one field and one getter and one setter

    final JCodeModel cm = new JCodeModel ();
    final JDefinedClass jClass = cm._package ("org.example")._class ("MyFirstClass");
    final JFieldVar jField = jClass.field (JMod.PRIVATE, String.class, "text");

    // getter
    final JMethod jGet = jClass.method (JMod.PUBLIC, String.class, "getText");
    jGet.body ()._return (jField);

    // setter
    final JMethod jSet = jClass.method (JMod.PUBLIC, cm.VOID, "setText");
    final JVar jParam = jSet.param (String.class, "text");
    jSet.body ().assign (JExpr._this ().ref (jField), jParam);

Created Java code:

package org.example;

public class MyFirstClass {
    private String text;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

to top

My second class - the one with Javadocs

The second class enhances the first class with two constructor - one that has no argument and one that has a constructor parameter. Additionally Javadoc comments are created to make the code more explaining.

Note: for the rest of the examples no Javadocs are emitted for the sake of improved readability

    final JCodeModel cm = new JCodeModel ();
    final JDefinedClass jClass = cm._package ("org.example")._class ("MySecondClass");
    jClass.javadoc ().add ("This is my second class comment");
    jClass.javadoc ().addAuthor ().add ("JCodeModel authors");

    final JFieldVar jField = jClass.field (JMod.PRIVATE, String.class, "text");

    // Empty constructor
    JMethod jCtor = jClass.constructor (JMod.PUBLIC);
    jCtor.javadoc ().add ("This is a no-argument constructor");

    // Constructor with Parameter
    jCtor = jClass.constructor (JMod.PUBLIC);
    JVar jParam = jCtor.param (String.class, "text");
    jCtor.body ().assign (JExpr._this ().ref (jField), jParam);
    jCtor.javadoc ().add ("This is the constructor with a parameter");
    jCtor.javadoc ().addParam (jParam).add ("The new text to be set");

    // getter
    final JMethod jGet = jClass.method (JMod.PUBLIC, String.class, "getText");
    jGet.body ()._return (jField);
    jGet.javadoc ().add ("This is a getter");
    jGet.javadoc ().addReturn ().add ("The text value");

    // setter
    final JMethod jSet = jClass.method (JMod.PUBLIC, cm.VOID, "setText");
    jParam = jSet.param (String.class, "text");
    jSet.body ().assign (JExpr._this ().ref (jField), jParam);
    jSet.javadoc ().add ("This is a setter");
    jSet.javadoc ().addParam (jParam).add ("The new text to be set");

Created Java code:

package org.example;


/**
 * This is my second class comment
 * 
 * @author JCodeModel authors
 */
public class MySecondClass {
    private String text;

    /**
     * This is a no-argument constructor
     */
    public MySecondClass() {
    }

    /**
     * This is the constructor with a parameter
     * 
     * @param text
     *     The new text to be set
     */
    public MySecondClass(String text) {
        this.text = text;
    }

    /**
     * This is a getter
     * 
     * @return
     *     The text value
     */
    public String getText() {
        return text;
    }

    /**
     * This is a setter
     * 
     * @param text
     *     The new text to be set
     */
    public void setText(String text) {
        this.text = text;
    }
}

to top

Creating a switch statement

    final JCodeModel cm = JCodeModel.createUnified ();
    final JDefinedClass jClass = cm._package ("org.example")._class ("SwitchTest");

    final JDefinedClass jEnumClass = jClass._enum ("MyEnum");
    final JEnumConstant ca = jEnumClass.enumConstant ("A");
    final JEnumConstant cb = jEnumClass.enumConstant ("B");
    jEnumClass.enumConstant ("C");

    final JMethod m = jClass.method (JMod.PUBLIC, cm.VOID, "dummy");
    final JVar p = m.param (JMod.FINAL, jEnumClass, "enumParam");
    final JSwitch s = m.body ()._switch (p);
    s._case (ca).body ()._break ();
    s._case (cb).body ()._break ();
    s._default ().body ()._break ();

Create Java code:

package org.example;

public class SwitchTest {

    public void dummy(final SwitchTest.MyEnum enumParam) {
        switch (enumParam) {
            case A:
            {
                break;
            }
            case B:
            {
                break;
            }
            default:
            {
                break;
            }
        }
    }

    public enum MyEnum {
        A,
        B,
        C;
    }
}

to top

For-each loop

Creating a simple for-each loop in a static method.

    final JCodeModel cm = JCodeModel.createUnified ();
    final JDefinedClass cls = cm._package ("org.example")._class ("TestForEach");

    final JMethod m = cls.method (JMod.PUBLIC | JMod.STATIC, cm.VOID, "foo");

    final AbstractJClass jClassList = cm.ref (List.class).narrow (Integer.class);
    final JVar jVarList = m.body ().decl (JMod.FINAL, jClassList, "alist", cm.ref (ArrayList.class).narrowEmpty ()._new ());
    m.body ().add (jVarList.invoke ("add").arg (1));
    m.body ().add (jVarList.invoke ("add").arg (2));

    // The main for-each
    final JForEach foreach = m.body ().forEach (JMod.FINAL, cm.ref (Integer.class), "count", jVarList);

    // printing out the variable
    foreach.body ().add (cm.ref (System.class).staticRef ("out").invoke ("println").arg (foreach.var ()));

Create Java code:

package org.example;

import java.util.ArrayList;
import java.util.List;

public class TestForEach {

    public static void foo() {
        final List<Integer> alist = new ArrayList<>();
        alist.add(1);
        alist.add(2);
        for (final Integer count: alist) {
            System.out.println(count);
        }
    }
}

to top

Extended examples

Inner classes

    final JCodeModel cm = JCodeModel.createUnified ();
    final JDefinedClass aClass = cm._class ("org.test.DaTestClass");
    final JDefinedClass daInner1 = aClass._class ("Inner");
    final JDefinedClass daInnerInner = daInner1._class ("InnerInner");
    final JDefinedClass daInner2 = aClass._class ("DaTestClassInner");
    final JDefinedClass daInner2Inner = daInner2._class ("Inner2");

    aClass.method (JMod.PUBLIC, daInner1, "getInner");
    aClass.method (JMod.PUBLIC, daInnerInner, "getInnerInner");
    aClass.method (JMod.PUBLIC, daInner2, "getInner2");
    aClass.method (JMod.PUBLIC, daInner2Inner, "getInner2Inner");

    final JDefinedClass otherClass = cm._class ("org.test.OtherClass");
    otherClass.method (JMod.PUBLIC, daInner1, "getInner");
    otherClass.method (JMod.PUBLIC, daInnerInner, "getInnerInner");
    otherClass.method (JMod.PUBLIC, daInner2Inner, "getInner2Inner");
    otherClass.method (JMod.PUBLIC, aClass, "getOuter");

Created Java code org/test/DaTestClass.java:

package org.test;

public class DaTestClass {

    public DaTestClass.Inner getInner() {
    }

    public DaTestClass.Inner.InnerInner getInnerInner() {
    }

    public DaTestClassInner getInner2() {
    }

    public DaTestClassInner.Inner2 getInner2Inner() {
    }

    public class DaTestClassInner {

        public class Inner2 {
        }
    }

    public class Inner {

        public class InnerInner {
        }
    }
}

Created Java code org/test/OtherClass.java:

package org.test;

import org.test.DaTestClass.DaTestClassInner;

public class OtherClass {

    public DaTestClass.Inner getInner() {
    }

    public DaTestClass.Inner.InnerInner getInnerInner() {
    }

    public DaTestClassInner.Inner2 getInner2Inner() {
    }

    public DaTestClass getOuter() {
    }
}

to top

Variable argument method (varargs)

To create a method foo with variable arguments:

   final JCodeModel cm = new JCodeModel ();
    final JDefinedClass cls = cm._package ("org.example")._class ("TestVarArgs");
    final JMethod m = cls.method (JMod.PUBLIC, cm.VOID, "foo");
    m.param (String.class, "param1");
    m.param (Integer.class, "param2");
    // That is the VarArg param
    final JVar jParam3 = m.varParam (String.class, "param3");

    final JForLoop forloop = m.body ()._for ();
    final JVar jcount = forloop.init (cm.INT, "count", JExpr.lit (0));
    forloop.test (jcount.lt (jParam3.ref ("length")));
    forloop.update (jcount.incr ());

    forloop.body ().add (cm.ref (System.class).staticRef ("out").invoke ("println").arg (jParam3.component (jcount)));

    final JMethod main = cls.method (JMod.PUBLIC | JMod.STATIC, cm.VOID, "main");
    main.param (String [].class, "args");
    main.body ().add (cls._new ().invoke (m)
                 .arg ("Param1")
                 .arg (cm.ref (Integer.class).staticInvoke ("valueOf").arg (5))
                 .arg ("Param 3a")
                 .arg ("Param 3b"));

Create Java code:

package org.example;

public class TestVarArgs {

    public void foo(String param1, Integer param2, String... param3) {
        for (int count = 0; (count<param3 .length); count ++) {
            System.out.println(param3 [count]);
        }
    }

    public static void main(String[] args) {
        new TestVarArgs().foo("Param1", Integer.valueOf(5), "Param 3a", "Param 3b");
    }
}

to top

Rare use cases

TODO