javabyteman

Byteman: Location Specifiers not working on APIs of List/Maps


I am trying to use location specifier for List/Maps. Its not working when adding elements to it via their API. When I set the variable using =, it works.

import java.util.*;  

public class SimpleTest  
    {
         public static void main(String[] args)
         {         
           System.out.println("Java: Entering main");
           for (int i = 1; i <= 1; i++) 
           {
             loopTest(i);
             try
             {
                Thread.sleep(1000);
             }
             catch(InterruptedException e)
             {
                System.out.println(e);
             }  
           }                  
         }
         
         public static void loopTest(int i)
         {
           System.out.println("Java: Iteration " + i);
           Integer a;
           a=new Integer(1);
           a=new Integer(2);
           a=new Integer(3);
           System.out.println("Java: a is " + a);
           
           System.out.println(" *********************** ");
           //Creating a List  
                     List<String> list=new ArrayList<String>();  
                     //Adding elements in the List  
                     list.add("Mango");  
                     list.add("Apple");  
                     list.add("Banana");             
 
                     //Iterating the List element using for-each loop  
                     for(String fruit:list)
                     {  
                      System.out.println("Java: list is" + fruit);                        
                     }  
           
           //Re-init list
           list=Arrays.asList("foo", "bar");
           
           //Iterating the List element using for-each loop  
                     for(String fruit:list)
                     {  
                      System.out.println("Java: list (new) is" + fruit);                      
                     }  
         }
    }

Byteman rule:

RULE trace main entry
CLASS SimpleTest
METHOD main
AT ENTRY
IF true
DO System.out.println("Byteman detected you are entering main - test")
ENDRULE

RULE catch_SimpleTest.loopTest
CLASS SimpleTest
METHOD loopTest
COMPILE
AT ENTRY
IF true
DO 
 System.out.println("Byteman Enter loopTest - " + $1)
ENDRULE

RULE catch_SimpleTest.loopTest0
CLASS SimpleTest
METHOD loopTest
COMPILE
AFTER WRITE $a 0
IF true
DO 
 System.out.println("Byteman loopTest0: " + $a)
ENDRULE

RULE catch_SimpleTest.loopTest1
CLASS SimpleTest
METHOD loopTest
COMPILE
AFTER WRITE $a 1
IF true
DO 
 System.out.println("Byteman loopTest1: " + $a)
ENDRULE

RULE catch_SimpleTest.loopTest2
CLASS SimpleTest
METHOD loopTest
COMPILE
AFTER WRITE $a 2
IF true
DO 
 System.out.println("Byteman loopTest2: " + $a)
ENDRULE

RULE catch_SimpleTest.loopTest3
CLASS SimpleTest
METHOD loopTest
COMPILE
AFTER WRITE $a 3
IF true
DO 
 System.out.println("Byteman loopTest3: " + $a)
ENDRULE

RULE catch_SimpleTest.loopTestALL
CLASS SimpleTest
METHOD loopTest
COMPILE
AFTER WRITE $a ALL
IF true
DO 
 System.out.println("Byteman loopTestALL: " + $a)
ENDRULE

RULE catch_SimpleTest.loopTestList1
CLASS SimpleTest
METHOD loopTest
COMPILE
AFTER WRITE $list 1
IF true
DO 
 System.out.println("Byteman loopTestList1: " + $list)
ENDRULE

RULE catch_SimpleTest.loopTestList2
CLASS SimpleTest
METHOD loopTest
COMPILE
AFTER WRITE $list 2
IF true
DO 
 System.out.println("Byteman loopTestList2: " + $list)
ENDRULE

RULE catch_SimpleTest.loopTestList3
CLASS SimpleTest
METHOD loopTest
COMPILE
AFTER WRITE $list 3
IF true
DO 
 System.out.println("Byteman loopTestList3: " + $list)
ENDRULE

Byteman output:

Byteman output screenshot

I expected after each add operation like list.add("Mango"); etc, a rule should be triggered, but it's not.
As can be seen, when I use =, again list=Arrays.asList("foo", "bar"); rule is triggered. It seems = is the only operator that is seen by Location logic.


Solution

  • You are misunderstanding the AFTER WRITE location specifier. When you specify

    AFTER WRITE list

    that identifies a place in the code where var is initialized or assigned. So it would match a statement like

    List list = new LinkedList()

    or

    list = new ArrayList(3)

    It will not match a statement like

    list.add("banana")

    because that statement does not initialize or assign a value to variable list.

    If you want to trigger a rule when the add method is called you need to specify a call location:

    AT CALL add

    That will match the first call to method add. You can also include a count

    AT CALL add 3

    or use the keyword ALL to make your rule match every call to add.