Around method in DJ

Pengcheng Wu (wupc AT ccs . neu . edu)


DJ is an pure Java library to support adaptive programming which separates the cross-cutting concerns of object structure traversal and the computation along with the traversal. To support the structure-shy style of object structure traversal, DJ provides the capability to generate traversal paths from traversal specifications (Strategy) at run time; to do meaningful computations, DJ supports Visitor pattern, which allows users to attach their customized Visitor objects to be executed. But there are two limitations on the traversal and Visitors:

  • The computations in the Visitor class (or its sub classes) can only be executed by side effects, i.e., all the user defined Visitor methods can not have return values and all the information about the computations have to be recorded manually in the Visitor classes and maintained by side effects;
  • Once the traversal paths have been computed, the users' programs have no power to change the traversal paths at run time, e.g., change the orders of traversing objects, decide not to go down to some edges which are in the traversal graph.
Limitation 1 disables functional-style computation combinations, which are desirable for a lot of recursive computation scenarios. Limitation 2 disables the flexibility of users to control the traversal according to the computation of Visitor itself. Functional Visitor was proposed to solve these two limitations.


If you are using DJ on Windows/Linux, copy the functionrt.jar to your computer and put it in the CLASSPATH and make sure it appears in front of the default DJ run time library (make sure you use DJ 0.8.5, which is available from DJ 0.8.5). If you are using CCS's UNIX machines, then just put

in your CLASSPATH and, again, make sure it appears in front of the default DJ run time library. Then you can use it in the same way as you are using the default DJ package, except it provides more interfaces to access, as shown in the following.

An Example

This example is to show a typical usage of the Functional Visitor, which handles with the problem of checking recursively a Container, which may include a list of sub Containers or Simple objects, to make sure each of the Container objects reachable from the source Container object is not overloaded. COM3360/COM1205 students may be familiar with the class structure and may remember how we solve this problem in the default DJ package, in which we have to maintain a stack structure to keep track of what the total weight of the currently traversed Container. Now we can solve this problem more elegantly. Here is a part of the source code.


class DifferenceVisitorDJ extends FunctionVisitor {

  public Object combine(Object[] values) {
    int total=0;

    for(int i=0; i<values.length; i++) {
           total+= ((Integer)values[i]).intValue();

    return new Integer(total);


  Object around(Weight w,Subtraversal st) {
    return w.get_i();

  Object around(Container c,Subtraversal st) {
    Integer total = (Integer)st.apply("contents");

    if(total.intValue() > c.get_capacity().get_i().intValue())
       System.out.println(" A Overloaded Container");

    return total;


class Main {
   static public void main(String args[]) throws Exception {
     ClassGraph cg=new ClassGraph(true,false);
     Container a = Container.parse(;

     TraversalGraph allWeights = new TraversalGraph(
        "from Container bypassing -> *,tail,* to Weight",cg);

     FunctionalOGS fogs=new FunctionalOGS(a,allWeights);

     fogs.traverse(new DifferenceVisitorDJ());


To access all of the source code, click here

Typical Usage

As you may have seen from the example, what is different from the usages of the default DJ package includes:

  • You need to create an object of FunctionalOGS, which is a subclass of ObjectGraphSlice, to do the traverse. The traverse method of FunctionalOGS only accepts one argument which is an instance of FunctionVisitor;
  • In a sub class of FunctionVisitor, besides the methods you can define before, such as, void before(..), void after(..), you can also define two kinds of visitor methods which have the return value (Object), i.e., Object around(SomeClass host, Subtraversal st) and Object combine(Object[] values).
  • The semantics (informal) of the around method is as follows: when the traversal reaches an object whose type matches SomeClass , the return value of the traversal on this object is determined by the return value of this around method. The return value is available to its parent object for further combination. The Subtraversal class is provided by the run time library and the object will be passed to the around method automatically at run time.
  • On the Subtraversal object, you can specify which part of the traversal you would like to go down. There are 4 interfaces available to users:
Object apply(String label)  go down to the edge labeled as label and return the value from the sub traversal;

Object[] applySuper() go up each of the inheritance edges and get the return values from each of the inheritance edge as an array of Object;

Object[] applyElements(String label) go down to the repetition edge labeled as label and get the return values from each of the elements as an array of Object;

Object[] apply() go down to all the edges from the class and get the return values from each edge as an array of Object.

In your around method, the control of the traversal is on your side, i.e., the traversal will not go further from the class unless you instruct it to do so in one of the above 4 ways.
  • If you don't define around method on a class, then the default combine semantics will be applied automatically to the array of Object which get from each of the edges from the class. The way you want to combine is specified as public Object combine(Object[] values).
  • If you don't define any around or combine method in a visitor class, then it will behave just the same as an ordinary DJ visitor.