How to Accumulate and Modify Values into Variable Using Mule 4 and DataWeave 2?

06 Oct, 2020 | 4 minutes read

Very often when we are working with values and variables, we need to store some value in a variable and modify that value when needed. If you are a senior developer working with MuleSoft values and variables, you have probably noticed that after the initial assignment of a variable, we cannot change that value in DataWeave transformation.

While working with variables in Mule 4 and DataWeave, we have come to the solution to the previously mentioned problem. Therefore, in this blog post, we will explain how to store, modify, and use a variable value at any stage of the DataWeave script into a single transform message by using the accumulator pattern in DataWeave 2 and Java HashMap class.

To use the java HashMap class we need to import the java module (Check Image 1).

Import Java Module
(Image 1 – Import Java Module)

One of the core parts of the accumulator pattern is to initiate a variable that we are going to use as an accumulator. In our case, we are going to use “accumulatorVar” which contains four keys with the initial values of different data types (Check Image 2).

Accumulator Variable
(Image 2 – Accumulator Variable)
Accumulator Flow
(Image 3 – Accumulator Flow)

After the initialization of the accumulator variable “accumulatorVar” we can use the below functions to accumulate the values.

fun accumulateValues (varName, keyName, add) =
using (addValue =
     Java::invoke(			                   //invoke java.util.HashMap
	    'java.util.HashMap',
    'put(Object,Object)',	                         //method used to add values
	     varName,                               //variable for accumulating values
		  {
		     arg0: keyName,                                          // key name
		     arg1: add( Java::invoke(              //add to accumulator variable
                    'java.util.HashMap',
                    'get(Object)',                         //method used to get value
                     varName,
                     {arg0: keyName}
                                )
          			         )
				           }
			            )
		             )
 Java::invoke('java.util.HashMap', 'get(Object)', varName, {arg0: keyName})  //return

The function “accumulateValues” is the Java::invoke DataWeave function to invoke put(Key, Value) method from java.util.HashMap class. To update the value from the accumulator variable first, we need to get the current value using the get(Key) method and after we get the value from the accumulator variable we add a new value and store the updated value in the same variable.

Let’s see how this function works on a simple mathematical example:

[1,2,3] map (value,index) -> {
	("Iteration " ++ index + 1) : accumulateValues (
vars.accumulatorVar, 'intKeyName', (accVar) -> accVar + value
       )
    }

We pass three parameters to the function “accumulateValues”:

  1. Accumulator variable (“accumulatorVar”)
  2. Name of the key where we want to accumulate value (“intKeyName”)
  3. Lambda function to sum the values (accVar) -> accVar + value

In the DataWeave script above, the key “intKeyName” of the variable “accumulatorVar” starts with an initial value of 0. We iterate through the list three times using the map operator and “value” has the value from the current iteration. In each iteration, the key “intKeyName” from “accumulatorVar” variable is reassigned with a new value which is the sum of the old value plus the current value ((accVar) -> accVar + value) but we can also use all other mathematical operations.

Result:

[
    {
        "Iteration 1": 1
    },
    {
        "Iteration 2": 3
    },
    {
        "Iteration 3": 6
    }
]

We can confirm that after the execution of the transform message the Logger component will print value 6 for vars.accumulatorVar.intKeyName variable.

Additionally, we will explore the example of accumulating Dataweave String concatenation values in different stages of the DataWeave script and the usage of different String operations like concatenate and replace.

[
  {
   "str1": accumulateValues (
             vars.accumulatorVar, 'strKeyName', (accVar) -> accVar ++ "Mule"
                 )
	   },
  {
    "list": [{
		"str2": accumulateValues (
vars.accumulatorVar, 'strKeyName', (accVar) -> accVar ++ "Soft"
    ),
		"num1": 1
		}]
	   },
  {
    "str3": accumulateValues (
      vars.accumulatorVar, 'strKeyName', (accVar) -> accVar replace "Soft" with " 4"
              )
	   }
]

In the dataweave script above, the key “strKeyName” of the variable “accumulatorVar” starts with the initial value “” (empty String).

In the first invocation of “accumulateValues” function we concatenate “Mule” with the initial value “” (empty String) and the value of “strKeyName” is reassigned with the new value “Mule”.

In the second invocation, we concatenate the old value “Mule” with the new value “Soft” and the value of “strKeyName” is reassigned with the new value “MuleSoft”.

In the last invocation, the String “Soft” from the old value “MuleSoft” is replaced with “4” and reassigned the value to “Mule 4”.

Result:

[
  {
    "str1": "Mule"
  },
  {
    "list": [
      {
        "str2": "MuleSoft",
        "num1": 1
      }
    ]
  },
  {
    "str3": "Mule 4"
  }
]

We can confirm that after the execution of the transform message, the Logger component will print the value for each in Mule 4 for vars.accumulatorVar.strKeyName variable.

Additionally, we will explore an example of accumulating Objects and see how we can accumulate the current value and assign another value to the key where we invoke the “accumulateValues” function.

To achieve this, we need to update the “accumulateValues” function:

1. Add new parameter “return

2. Dataweave Replace the last line of “accumulateValues” function with “return

[
	{
		"obj1": accumulateValues (
	vars.accumulatorVar, 'listKeyName', (accVar) -> accVar + {"key1": "value1"},
    {"key1": upper("value1")}
   		 			)
	},
	{
		"list1": [{
				"obj2": accumulateValues (
vars.accumulatorVar, 'listKeyName', (accVar) -> accVar + {"key2": "value2"}, {}
    				)
			}
		]
	},
	{
		"listAllObj": Java::invoke(
'java.util.HashMap', 'get(Object)', vars.accumulatorVar,{arg0: 'listKeyName'}
)
	}
]

In the DataWeave script above we are invoking “accumulateValues” function using “accumulatorVar” variable and key “listKeyName” with initial value [] (empty Array). We invoke the function in different stages of the DataWeave script and add Objects into the Array. The result of the accumulation is used only at the key “listAllObj”.

Result:

[
    {
        "obj1": {
            "key1": "VALUE1"
        }
    },
    {
        "list1": [
            {
                "obj2": {}
            }
        ]
    },
    {
        "listAllObj": [
            {
                "key1": "value1"
            },
            {
                "key2": "value2"
            }
        ]
    }
]

To sum up, now you know how to accumulate values into a set variable in DataWeave Mule 4. Having the ability to store values in a variable and modify that value when you most need it is really important. Not only does it reduce the developer’s time, but it also enhances the developer’s skills. In our blog post, you were able to see the function that accumulates values in a variable and how to accumulate all data types in different stages of the DataWeave script.

If you need more information about how to set variables in Mule 4 or our solution for anything else you want to discuss, feel free to contact us. Additionally, we have the same solution in Mule 3, so if you are interested in it, you can contact us as well.