Mule esb 3.8 how to add variable into payload? - mule

let say I have payload:
{ Name=User1, Age=29 }
and variable:
{ Address=Planet Earth}
I want to have a check if that variable not null then add it into payload.
So final result will be:
{ Name=User1, Age=29, Address=Planet Earth }
How? Was try via payload.Put(variable) but that not allow me such.

With DataWeave using a Transform component you can use the expression: payload ++ flowVars.variable
If you don't want or can't use DataWeave then you can use a MEL expression that uses the Java method Map.putAll() of the Map interface. You can not use <set-payload> because it doesn't return a value. Instead you can use the <expression-component> component.
Example:
<expression-component doc:name="Expression"><![CDATA[payload.putAll(flowVars.variable)]]></expression-component>

Related

"ByteArrayBasedCursorStreamProvider cannot be cast to HttpRequestAttributes" when trying to set attributes before APIKit

I have a requirement on my REST API where I might set some attributes before APIKit if some condition is met (because we have a logger which must write this information).
Following this solution, I created the script below to set Attribute object inside Transform component.
%dw 2.0
output application/json
---
(
(attributes
- "headers"
- "maskedRequestPath")
++
({
headers: attributes.headers
++
{
xpto: 123
}
})
)
as Object {
class: "org.mule.extension.http.api.HttpRequestAttributes"
}
However, I am getting org.mule.weave.v2.el.ByteArrayBasedCursorStreamProvider cannot be cast to org.mule.extension.http.api.HttpRequestAttributes error.
Is there a way where I can successfully set these values before APIKit Router?
I am using APIKit v1.6.1, with 4.3.0 runtime.
You should use output application/java in order to create an HttpAttributes

How to set array property value in code using Carina Test Framework for API tests?

I have the following request json body:
{
...
"attachmentIds": "${attachments}"
...
}
I have a properties file that includes the declaration of the corresponding placeholder
I want to set array of strings in code instead of "attachments" placeholder, but getProperties().setProperty() expects only string value.
How can I achieve it other way or is it possible at all?
Thanks!
As an option you can transform your array into the String in java code. And then pass this String as property value.
Another option, you can pass String array from code and then parse it in your json template.
For example:
String[] arr = { "1", "2", "3" };
apiMethod.addProperty("attachments", arr);
And then in your json:
{
"attachmentIds": [<#list attachments as val>"${val}"<#if val?has_next>,</#if></#list>]
}
Check freemarker documentation to get more details:
https://freemarker.apache.org/docs/ref_builtins_loop_var.html
Also please note that some of freemarker functions (including has_next) are available only in newest versions of library. So make sure to add into your dependencies list. Carina is now in process of migrating to latest freemarker version.

mule : Merge List of maps into single Map

I have scattergather in my flow, the output of which is a List of Maps, How can I convert that into a single Map in mule?
I have tried combine-collections-transfomer, flatten payload. Nothing seems to be working.
You can you following dataweave code, but it will override duplicate keys
%dw 1.0
%output application/java
---
{(payload)}
Hope this helps.
I would recommend using a custom Java Transformer so you can easily handle special situations such as duplicate keys with different values. A DataWeave function may also be able to do the trick, but you'll need Mule EE.
With a Transformer it's a simple question of Java code:
public class MyMapFlattener extends AbstractMessageTransformer{
public Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException {
//assuming your payload is the list of map
List<Map<?, ?>> listOfMap = message.getPayload();
Map<Object, Object> finalMap = new HashMap<Object, Object>();
for(Map<?, ?> map : listOfMap){
//you can use putAll if you don't care about duplicates
//finalMap.putAll(map);
// or a more complex algorithm to handle duplicates
for(Entry<?, ?> e : map.entrySet()){
if(finalMap.containsKey(e.getKey())){
//do something to handle situation when key is duplicate...
//you may want to check if both values are equals and skip this
//maybe throw an exception if values are different
//or keep a value
throw new Exception("Duplicate: " + e);
} else {
//key does not exists, put it
finalMap.put(e.getKey(), e.getValue());
}
}
}
return finalMap;
}
}
And then use this transformer in your flow. See the docs for details.
You have multiple ways of doing this one of which is flatten operator which merges 2 arrays into a single array. The other is to do it through the Dataweave Transform map operator and merging them as per your requirements.

How to use MEL in dataweave to replace characters in a string

I am using Anypoint Studio 6.1 and Mule 3.8.1 and have this MEL expression that replaces any text \n with a new line/carriage return.
payload.replace('\\n', System.getProperty('line.separator'))
I would like to move this functionality into Dataweave but cannot get the MEL expression to work or find a way to do this in Dataweave.
How can I reuse the MEL expression in Dataweave?
Thanks
You should investigate Global Functions
Like:
<configuration doc:name="Global MEL-Functions">
<expression-language>
<global-functions file="mel/extraFunctions.mvel">
</global-functions>
</expression-language>
</configuration>
And create your the global function in a resoruce file for reuse
def UUID() {
return java.util.UUID.randomUUID().toString();
}
def decode(value) {
return java.util.Base64.getDecoder().decode(value);
}
def encode(value) {
return java.util.Base64.getEncoder().encodeToString(value.getBytes());
}
def stringToAscii(value) {
StringBuilder sb = new StringBuilder();
for (char c : value.toCharArray())sb.append((int)c);
return new BigInteger(sb.toString());
}
And reference your global functions in your dataweave
payload map
{
target: stringToAscii($) as :string
}
DW is its own mini-language within Mule aside from MEL is how it was described to me and uses a different syntax to do what you are trying. I have not done new lines specifically as my DW expressions use line separators as record separators, but the same general tactic should work. Here is an example of changing commas to spaces within a dw payload mapping:
AcctID: $.ACCOUNT_ID replace "," with " ",

How do you set message properties in Mule using Groovy?

How do you set message properties in Mule using Groovy?
I need to set a message property from within a Groovy Scripting Component. Documentation on the subject does not appear to be easy to find.
You can set individual properties as follows:
message.setInvocationProperty('myFlowVariable', 'value') // sets a flow variable, like <set-variable/>
message.setOutboundProperty('myProperty', 'value') // sets an outbound message property, like <set-property/>
message.setProperty('myInboundProperty', 'value', PropertyScope.INBOUND) // sets an inbound property
In the scripting component you have available the message binding that is an instance of org.mule.api.MuleMessage, thus you can use the method org.mule.api.MuleMessage.addProperties(Map, PropertyScope) to add any property you need.
It depends on which version of Mule EE (and so then Groovy) you are using, but in recent versions of Mule (3.7.x) the easiest way is:
flowVars ['name_of_variable'] = 'value'
flowVars ['name_of_variable'] = 14
This for variables with Invocation scope, if you wan to store variable for Session scope, then:
sessionVars ['name_of_variable'] = 'value'
sessionVars ['name_of_variable'] = 14
Please use this site from Mulesoft for Scripting as reference.
https://docs.mulesoft.com/mule-user-guide/v/3.7/script-component-reference
Here is how I figured it out:
add schema to your flow if missing:
xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting"
http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd
now let's set session-variable 'account' with a custom Foo object using Groovy:
<scripting:transformer doc:name="Script">
<scripting:script engine="groovy"><![CDATA[
com.test.Foo f = new com.test.Foo();
f.setAccountId('333');
return message.setSessionProperty('account',f);]]>
</scripting:script>
</scripting:transformer>
above script will turn your Payload to NullPayload, because it is a transformer. If that' a concern, try this instead:
<enricher target="#[sessionVars['account']]">
<scripting:transformer doc:name="Script">
<scripting:script engine="groovy"><![CDATA[
com.test.Foo f = new com.test.Foo();
f.setAccountId('333');
return f;]]>
</scripting:script>
</scripting:transformer>
</enricher>
Enjoy. :)