javasun-codemodeljcodemodel

JCodeModel - How to chain invoke methods


I am trying to figure out how to use a loop to build a JExpression that I can use in an .assign() call. I know that you can do something like JExpr.invoke("methodA").invoke("methodB") with JCodeModel, but I want to be able to add each .invoke() method based on a list of method names. Does anyone know how to do this?

Example of my Generator code [this is assuming that I have modified the ArrayList.add() method to return the ArrayList]:

JDefinedClass newClass = jCodeModel._class("com.me.GeneratedClass");
JClass refObject = jCodeModel.ref(Object.class);
JClass refArrayList = jCodeModel.ref(ArrayList.class);

JFieldVar objectList = newClass.field(refArrayList, "objects");

JBlock methodBody = newClass.method(JMod.PUBLIC, refArrayList, "getNewObjectList");

String[] methodsToInvoke = {"add", "add", "add"};

JExpression rhsAssignmentExpression = JExpr._new(refArrayList).narrow(refObject);
for(String methodName : methodsToInvoke) {
    rhsAssignmentExpression.invoke(methodName).arg(JExpr._new(refObject));
}

methodBody.assign(objectList, rhsAssignmentExpression);
methodBody._return(objectList);

Example of what I am trying to generate:

class GeneratedClass {

   ArrayList<Object> objects;

   public ArrayList<Object> getNewObjectList()
   {
      objects = new ArrayList<Object>().add(new Object()).add(new Object()).add(new Object());
      return objects;
   }
}

My problem is that this method doesn't chain the invoke methods, but replaces them so the generated code looks like this:

class GeneratedClass {

   ArrayList<Object> objects;

   public ArrayList<Object> getNewObjectList()
   {
      objects = new ArrayList<Object>().add(new Object());
      return objects;
   }
}

Solution

  • What you will need to do is store an intermediate value for each invoke() JExpression call:

    JExpression rhsAssignmentExpression = JExpr._new(refArrayList);
    for(String methodName : methodsToInvoke) {
        rhsAssignmentExpression = rhsAssignmentExpression.invoke(methodName).arg(JExpr._new(refObject));
    }
    

    This avoids redefining the invocation each time, and effectively chains the calls. The result is the following:

    public class GeneratedClass {
    
        public ArrayList objects;
    
        public ArrayList getNewObjectList() {
            objects = new ArrayList().add(new Object()).add(new Object()).add(new Object());
            return objects;
        }
    
    }